กระรอกดินต้นฉบับกำลังขยายถาดชิ้นงานแล้วตัดพื้นที่สำรองส่วนเกินบนโต๊ะสีมิ้นต์

Go slices.Grow กับ Clip: จองความจุให้พอ แล้วคืนส่วนเกินตรงขอบงาน

พี่โชว์Engineering

รู้จำนวนสมาชิกที่จะเติมคร่าว ๆ แต่ปล่อยให้ append ขยาย backing array ไปเรื่อย ๆ เราอาจจ่ายค่าจองและคัดลอกหลายรอบโดยไม่จำเป็นครับ slices.Grow จองที่ว่างสำหรับสมาชิกเพิ่มล่วงหน้า ส่วน slices.Clip ลด capacity ให้เท่ากับ length เมื่อข้อมูลกำลังออกจากขั้นตอนสร้าง

WHY: length กับ capacity เป็นคนละสัญญา

Grow(s, n) ไม่เพิ่มสมาชิกและไม่เปลี่ยน length มันรับประกันเพียงว่า append อีก n ค่าได้โดยไม่ต้องจองใหม่ ถ้าความจุเดิมพอ ฟังก์ชันอาจคืน slice ที่ใช้ backing array เดิม เหมือนแจ้งร้านข้าวว่าจะมีลูกค้าเพิ่มเพื่อเตรียมโต๊ะ แต่ยังไม่ได้เสิร์ฟจานเปล่า

Clip ทำอีกหน้าที่หนึ่ง: สร้าง slice ที่มี capacity เท่ากับ length เพื่อไม่ให้ผู้รับเห็นพื้นที่สำรองก้อนใหญ่โดยไม่ตั้งใจ การ clip ไม่ได้ทำให้หน่วยความจำคืนระบบปฏิบัติการทันทีทุกกรณี และไม่ใช่คำสั่งล้างข้อมูลลับ แต่ทำ ownership boundary ให้อ่านง่ายขึ้น

package main

import (
	"slices"
	"testing"
)

func buildBatch(seed []int, incoming []int) []int {
	batch := slices.Clone(seed)
	batch = slices.Grow(batch, len(incoming))
	batch = append(batch, incoming...)
	return slices.Clip(batch)
}

func TestBuildBatch(t *testing.T) {
	seed := []int{10, 20}
	got := buildBatch(seed, []int{30, 40, 50})
	if !slices.Equal(got, []int{10, 20, 30, 40, 50}) {
		t.Fatalf("unexpected values: %v", got)
	}
	if cap(got) != len(got) {
		t.Fatalf("Clip must cap at length: len=%d cap=%d", len(got), cap(got))
	}
	got[0] = 99
	if seed[0] != 10 {
		t.Fatal("Clone should isolate the caller's slice")
	}
}

ใช้เมื่อไร และอย่าใช้เมื่อไร

ใช้ Grow เมื่อมี batch size, header count หรือ upper bound ที่เชื่อถือได้ หากค่าประมาณมาจากผู้ใช้ อย่าจองตามตัวเลขดิบ เพราะ request เล็กอาจบังคับให้ process จองหน่วยความจำก้อนใหญ่ ควร clamp เพดานก่อนเสมอ

ใช้ Clip เมื่อส่ง slice ที่สร้างเสร็จออกจาก builder หรือเก็บระยะยาว แต่ถ้ายัง append ต่อทันที การ clip แล้ว grow ใหม่เพียงสร้างงานเพิ่ม สำหรับข้อมูลลับต้องล้างสมาชิกตาม threat model ก่อนปล่อย reference; capacity ที่เล็กลงไม่เท่ากับการลบ byte จาก memory

Recap

  • Grow จอง capacity เพิ่ม แต่ไม่เพิ่ม length
  • จองจากขนาดที่ validate และมีเพดาน
  • Clip เหมาะตรง boundary หลังสร้างเสร็จ
  • Clip ไม่ใช่ secure erase หรือคำสั่งคืน RAM ทันที