Go strings.FieldsFuncSeq: แยก token แบบ iterator ไม่ต้องสร้าง slice ทั้งก้อน
การแยกข้อความเป็น token มักจบด้วย slice ก้อนใหญ่ ทั้งที่ผู้เรียกต้องการแค่สามค่าหน้า strings.FieldsFuncSeq คืน iterator แบบ iter.Seq[string] จึงเดินผลลัพธ์ทีละค่าและหยุดลูปได้ โดยไม่ต้องสร้าง slice ของ token ทั้งหมดก่อนครับ
WHY: จ่ายเท่าที่อ่าน
ให้นึกถึงร้านข้าวแกงที่ตักกับข้าวทีละถาด เราหยุดเมื่อจานครบ ไม่ต้องยกทุกถาดมากองบนโต๊ะ FieldsFuncSeq เหมาะกับ log, header หรือคำสั่งยาวที่ต้องอ่าน prefix ก่อนตัดสินใจ และช่วยให้ pipeline ต่อกับ range ได้ตรง ๆ
package content
import (
"slices"
"strings"
"testing"
"unicode"
)
func FirstNWords(input string, n int) []string {
if n <= 0 { return nil }
out := make([]string, 0, n)
for word := range strings.FieldsFuncSeq(input, unicode.IsSpace) {
out = append(out, strings.Clone(word))
if len(out) == n { break }
}
return out
}
func TestFirstNWords(t *testing.T) {
got := FirstNWords(" เช้า\tกลางวัน เย็น ค่ำ ", 3)
want := []string{"เช้า", "กลางวัน", "เย็น"}
if !slices.Equal(got, want) { t.Fatalf("got %q", got) }
if got := FirstNWords("หนึ่ง สอง", 0); got != nil { t.Fatalf("want nil: %q", got) }
}
HOW: separator คือ predicate
ฟังก์ชันที่ส่งเข้าไปตอบว่า rune ใดเป็นตัวคั่น ตัวอย่างใช้ unicode.IsSpace จึงรองรับช่องว่างหลายชนิด ถ้าจะคั่น comma หรือ semicolon ให้เขียน predicate ให้ชัด แต่อย่าให้มี side effect เพราะลำดับและจำนวนครั้งที่ถูกเรียกไม่ควรกลายเป็น business contract
ค่าที่ yield อ้างอิงช่วงใน string ต้นฉบับ ถ้าจะเก็บ token อายุยาวหลัง input ก้อนใหญ่มากหมดหน้าที่ ให้ strings.Clone เฉพาะค่าที่เก็บเพื่อตัดการอ้างอิง backing storage ส่วน pipeline ที่ใช้แล้วทิ้งทันทีไม่จำเป็นต้อง clone ทุกค่า
FieldsFuncSeq จะข้ามกลุ่มตัวคั่นติดกันและไม่คืน token ว่าง ถ้ารูปแบบข้อมูลถือช่องว่างระหว่าง delimiter ว่าเป็น field จริง ต้องใช้ parser ที่รักษา empty field เช่น CSV parser แทน การเลือก API จึงขึ้นกับสัญญาข้อมูล ไม่ใช่แค่ความสั้นของโค้ด
Recap
- ใช้ iterator เมื่ออ่านทีละค่าและอาจหยุดก่อนจบ
- predicate ต้องนิยาม delimiter ไม่ใช่ validation ทั้ง record
- clone เฉพาะ token ที่ต้องเก็บนาน
- อย่าใช้เมื่อ empty field มีความหมาย
- ทดสอบ input ว่าง ตัวคั่นติดกัน Unicode และการหยุดก่อนจบ