Go slices.Chunk: แบ่ง batch โดยไม่เปิดช่องให้ append ทับข้อมูลข้างเคียง
งานส่ง API, เขียนฐานข้อมูล หรือประมวลผลไฟล์มักต้องแบ่ง input เป็นก้อนขนาดคงที่ โค้ดแบบ for start := 0; start < len(values); start += size ทำได้ แต่ต้องคำนวณปลายช่วงเองและคุมกรณีก้อนสุดท้ายทุกครั้ง slices.Chunk ทำเรื่องนี้เป็น iterator มาตรฐาน: รับ slice กับขนาดสูงสุด แล้ว yield subslice ที่ต่อเนื่องกันครับ
จุดที่น่าสนใจกว่าความสั้นคือทุกก้อนถูก clip capacity ให้เท่ากับ length สมมติ batch แรกยาว 3 การ append สมาชิกที่สี่จะต้องจัด backing array ใหม่ จึงไม่เขียนทับสมาชิกต้นก้อนถัดไปโดยบังเอิญ อย่างไรก็ดี สมาชิกเดิมใน batch ยังแชร์ storage กับ input การแก้ batch[0] จึงสะท้อนกลับไปยัง slice ต้นทาง
package main
import (
"fmt"
"slices"
)
func main() {
values := []int{10, 20, 30, 40, 50, 60, 70}
var sizes []int
for batch := range slices.Chunk(values, 3) {
sizes = append(sizes, len(batch))
if len(batch) != cap(batch) {
panic("Chunk must clip each batch capacity")
}
}
if !slices.Equal(sizes, []int{3, 3, 1}) {
panic(fmt.Sprintf("unexpected sizes: %v", sizes))
}
first := slices.Collect(slices.Chunk(values, 3))[0]
appended := append(first, 99)
if values[3] != 40 || appended[3] != 99 {
panic("append crossed a batch boundary")
}
fmt.Println(sizes)
}
ใช้ให้ตรงสัญญา
Chunk จะ panic เมื่อ n < 1 ดังนั้นค่าที่มาจาก config หรือ request ต้อง validate ก่อน ถ้า input ว่าง iterator ไม่ yield อะไร ซึ่งต่างจากบาง helper ที่อาจคืนหนึ่งก้อนว่าง อีกด้านหนึ่ง iterator ช่วยให้หยุดก่อนครบทุกก้อนได้ จึงเหมาะกับ pipeline ที่อาจเจอ error กลางทางและไม่ต้องสร้าง [][]T ทั้งก้อนล่วงหน้า
หาก worker ทำงานขนานและแก้สมาชิกใน batch ต้องพิสูจน์ว่าแต่ละ batch ไม่ซ้อนกันจริงและไม่มี goroutine อื่นแตะ input พร้อมกัน แม้ capacity ถูก clip ก็ไม่ได้เปลี่ยน subslice ให้เป็นสำเนา ถ้าต้องส่ง ownership ออกจากขอบเขตหรือเก็บไว้นานกว่าต้นทาง ให้ clone แต่ละก้อนด้วย slices.Clone ก่อน
Recap
Chunkลด arithmetic ของขอบช่วงและจัดการก้อนสุดท้ายให้len(batch) == cap(batch)กัน append ไหลเข้าก้อนถัดไป แต่สมาชิกยังแชร์ storage- validate ว่าขนาด batch มากกว่าศูนย์
- clone เมื่อผู้รับต้องถือ ownership หรือแก้ข้อมูลอิสระครับ