กระรอกดินต้นฉบับส่งคู่กุญแจและค่าจากสายพานเข้าสู่กล่องแผนที่บนฉากมิ้นต์

Go maps.Insert: เติม map จาก iterator โดยไม่ต้องเขียน loop ซ้ำ

พี่โชว์Engineering

เวลาเรามีข้อมูลเป็นคู่ key/value จาก iterator แล้วอยากเทลง map ปลายทาง การเขียน for k, v := range seq ทุกจุดไม่ได้ผิด แต่ทำให้คำสั่งธุรกิจ “เอาชุดนี้ไปเติม map” จมหายอยู่ในพิธีการครับ ตั้งแต่ Go 1.23 maps.Insert รับ iter.Seq2[K, V] แล้วใส่ทุกคู่ให้ตรงความหมายในบรรทัดเดียว

ลองนึกถึงพนักงานส่งบัตรคิวเป็นคู่ “ชื่อโต๊ะ–จำนวนคน” ช่องรับไม่ต้องรู้ว่าคู่เหล่านั้นมาจาก slice, parser หรือ generator ขอเพียงส่งตามสัญญา Seq2 ก็พอ

package main

import (
    "fmt"
    "maps"
)

func activeScores(yield func(string, int) bool) {
    for _, item := range []struct {
        name  string
        score int
    }{{"mai", 7}, {"guy", 9}, {"mai", 10}} {
        if !yield(item.name, item.score) {
            return
        }
    }
}

func main() {
    scores := map[string]int{"old": 1}
    maps.Insert(scores, activeScores)

    if scores["mai"] != 10 || scores["guy"] != 9 || scores["old"] != 1 {
        panic("maps.Insert result is wrong")
    }
    fmt.Println(scores["mai"], scores["guy"])
}

คู่ที่มี key ซ้ำจะเขียนทับค่าก่อนหน้า ดังนั้นตัวอย่างได้ mai = 10 ไม่ใช่ 7 และ entry เดิมที่ไม่มี key ซ้ำยังอยู่ครบ ฟังก์ชันนี้จึงเป็น insert/overwrite ไม่ใช่ replace ทั้ง map หากต้องการ snapshot ใหม่ให้สร้าง map ใหม่ก่อน แล้วค่อย Insert

ลำดับของ map ใน Go ไม่รับประกัน อย่าพึ่งลำดับตอนอ่านผล และอย่าใช้เมื่อ key ซ้ำต้องถือเป็น error เพราะ Insert ไม่มี callback แจ้ง conflict กรณีนั้น loop ชัดกว่า: ตรวจ _, exists := dst[k] แล้วคืน error พร้อมบริบทได้

Recap

  • ใช้เมื่อข้อมูลต้นทางเป็น iter.Seq2 และกติกาคือเขียนทับได้
  • จำว่า map เดิมไม่ได้ถูกล้าง
  • ตรวจ key ซ้ำเองเมื่อ conflict เป็นข้อผิดพลาด
  • อย่าผูกผลลัพธ์กับลำดับ iteration ของ map