กระรอกดินต้นฉบับตรวจตะกร้าสามใบและหยิบผลไม้ชิ้นแรกที่ไม่ว่างบนฉากสว่าง

Go cmp.Or: เลือกค่าตัวแรกที่ไม่เป็น zero value แบบอ่านรู้เรื่อง

น้องกายEngineering

เวลาโปรแกรมมีค่าจากหลายชั้น เช่น flag, environment, ไฟล์ config และค่าเริ่มต้น เรามักต้องเลือก ค่าตัวแรกที่ใช้งานได้ ถ้าเขียน if ไล่ทีละชั้น โค้ดไม่ผิดแต่ความตั้งใจถูกกลบด้วยพิธีการครับ ตั้งแต่ Go 1.22 ฟังก์ชัน cmp.Or บอกกติกานี้ตรง ๆ: คืนค่าตัวแรกที่ไม่ใช่ zero value หรือคืน zero value หากทุกตัวว่าง

WHY: ให้ลำดับ fallback มองเห็นในบรรทัดเดียว

ลองนึกถึงร้านข้าวตามสั่งที่ถาม “เอาเมนูจากใบสั่ง ถ้าไม่มีใช้เมนูประจำโต๊ะ ถ้ายังไม่มีเอากะเพรา” ลำดับสำคัญกว่ากลไกการถาม cmp.Or ทำให้คนอ่านเห็นลำดับนั้นทันที และ generic ของมันทำงานกับชนิดที่ comparable ได้ เช่น string, number, bool, pointer และ struct ที่เปรียบเทียบได้

package main

import (
    "cmp"
    "fmt"
)

type Limits struct {
    Retries int
    Timeout int
}

func main() {
    name := cmp.Or("", "จากไฟล์", "ค่าเริ่มต้น")
    retries := cmp.Or(0, 3, 5)
    limits := cmp.Or(Limits{}, Limits{Retries: 3, Timeout: 10})

    if name != "จากไฟล์" || retries != 3 {
        panic("fallback order is wrong")
    }
    if limits.Retries != 3 || limits.Timeout != 10 {
        panic("struct fallback is wrong")
    }
    fmt.Println(name, retries, limits)
}

คำว่า zero value ไม่ได้แปลว่า “ข้อมูลเสีย” เสมอไป: ค่าว่าง, ศูนย์, false และ nil อาจเป็นค่าที่ผู้ใช้ตั้งใจ หากศูนย์หมายถึง “ไม่ retry” การส่งค่าศูนย์ตามด้วยสามจะเปลี่ยนเจตนาโดยเงียบ ๆ กรณีนั้นควรใช้ pointer, คู่ค่า value/ok หรือชนิด option เพื่อแยก “ไม่ได้ตั้ง” ออกจาก “ตั้งเป็นศูนย์”

เลือกใช้เมื่อกติกาคือ first non-zero จริง ๆ

cmp.Or เหมาะกับ fallback ที่ทุกค่ามีชนิดเดียวกันและ zero value หมายถึง “ข้าม” อย่างชัดเจน ไม่เหมาะกับ validation, การแปลงชนิด หรือ fallback ที่ต้อง log เหตุผล เพราะ argument ทุกตัวถูกประเมินก่อนเรียกฟังก์ชัน ถ้าตัวเลือกหลังมีงานแพงหรือ side effect ให้กลับไปใช้ if เพื่อทำแบบ lazy

Recap

  • เรียงค่าจากสำคัญที่สุดไป fallback สุดท้าย
  • ยืนยันว่า zero value แปลว่า “ไม่ได้ตั้ง” จริง
  • อย่าใส่งานแพงหรือ side effect ใน argument
  • ใช้ pointer หรือคู่ value/ok เมื่อศูนย์เป็นค่าที่ถูกต้อง