Go slices.Backward: วนจากท้ายโดยไม่กลับลำดับข้อมูลต้นฉบับ
บางงานต้องหาค่าล่าสุดก่อน เช่น event ล่าสุดที่ผ่านเงื่อนไข แต่ไม่อยากกลับลำดับ slice เพราะข้อมูลต้นฉบับยังถูกใช้ที่อื่นครับ slices.Backward คืน iterator ที่เดินคู่ index, value จากท้ายมาหน้าโดยไม่แก้ slice
WHY: แยก “ลำดับที่อ่าน” ออกจาก “ลำดับที่เก็บ”
การเรียก slices.Reverse เปลี่ยนข้อมูลจริง เหมือนสลับแฟ้มทั้งตู้เพื่อหยิบแฟ้มหลังสุด ส่วน Backward เหมือนเราเดินอ้อมไปเปิดตู้จากอีกด้าน แฟ้มยังอยู่ที่เดิม โค้ดที่ถือ slice เดียวกันจึงไม่เห็นผลข้างเคียง
HOW: range รับ index กับค่าได้ตรง ๆ
package main
import (
"fmt"
"slices"
)
func main() {
values := []int{10, 20, 30}
got := make([]int, 0, len(values))
indexes := make([]int, 0, len(values))
for index, value := range slices.Backward(values) {
indexes = append(indexes, index)
got = append(got, value)
}
if !slices.Equal(got, []int{30, 20, 10}) {
panic(got)
}
if !slices.Equal(indexes, []int{2, 1, 0}) {
panic(indexes)
}
if !slices.Equal(values, []int{10, 20, 30}) {
panic("input was mutated")
}
fmt.Println(got)
}
Backward คืน iter.Seq2 จึงเป็นการดึงค่าทีละคู่ ไม่ได้สร้าง slice กลับด้านอีกก้อน ถ้าต้องเก็บผลย้อนจริงค่อย append เหมือนตัวอย่าง แต่ถ้าแค่หาเจอแล้ว break จะหยุดได้ทันทีและไม่เสียหน่วยความจำตามขนาดข้อมูล
ข้อควรระวังคืออย่าแก้โครงสร้าง slice ระหว่างเดิน iterator เพราะ index ที่กำลังใช้ผูกกับ snapshot ของ header ตอนเริ่มอ่าน ถ้าต้องลบหรือย้ายสมาชิก ให้เก็บ index ที่พบแล้วค่อยแก้หลัง loop
Recap
- ใช้
Backwardเมื่อต้องอ่านท้ายไปหน้าแต่ไม่อยาก mutate - รับทั้ง index และ value ได้จาก
range - หยุดเร็วด้วย
breakได้โดยไม่สร้างสำเนา - แยกช่วงค้นหาออกจากช่วงแก้ slice