constraints, comparable, inference 1.27
เมื่อก่อนอยากได้ Min ทั้ง int และ float ต้องเขียน 2 รอบ:
func MinInt(a, b int) int { if a < b { return a }; return b }
func MinFloat(a, b float64) float64 { if a < b { return a }; return b }มี generics เขียนรอบเดียวจบ
func Min[T int | float64](a, b T) T {
if a < b { return a }
return b
}
Min(1, 2) // T=int
Min(1.5, 2.5) // T=float64
Min[int](1, 2) // เขียนชัดก็ได้[T int|float64] อ่านว่า "T เป็นได้แค่ int หรือ float64"
ทำกับ slice ได้:
func Map[T, R any](s []T, f func(T) R) []R {
out := make([]R, 0, len(s))
for _, v := range s { out = append(out, f(v)) }
return out
}any = อะไรก็ได้, comparable = เทียบ == ได้ (เอาไว้ทำ key map)
type Number interface { ~int | ~int64 | ~float64 }
// ~ = เอา type ที่ไส้เป็น int ด้วย เช่น type Age int ก็ได้Generic อ้างตัวเองได้แล้ว ทำโครงสร้างซับซ้อนง่ายขึ้น:
มือกลางรู้ว่ามีก็พอ ได้ใช้ตอนทำ lib ซับซ้อน
เมื่อก่อน method ห้าม generic ตอนนี้ได้แล้ว (ตัวอย่างจาก math/rand/v2):
และ compiler เดา type ให้ในที่ที่เคยต้องย้ำ:
func GenericFormatter[T any](v T) string { return fmt.Sprintf("value: %v", v) }
type IntFormatter func(int) string
formatters := []IntFormatter{GenericFormatter} // เดา T=int
fn := IntFormatter(GenericFormatter)
ch := make(chan IntFormatter, 1)
ch <- GenericFormatter // ส่งเข้า channel ก็เดาให้ถ้าเดาไม่ออกให้เขียนชัด GenericFormatter[int] อย่าฝืน
any + เทสต์ก่อนค่อยตีกรอบอ้างอิง: Go 1.26 release (recursive), Go 1.27 release (generic methods + inference incl. channel sends)
func IndexOf[T comparable](xs []T, want T) int {
for i, x := range xs {
if x == want {
return i
}
}
return -1
}func Sum[T ~int | ~float64](xs []T) T {
var total T
for _, x := range xs {
total += x
}
return total
}~ = รับ type พื้นฐานที่ตั้งชื่อใหม่ด้วย (เช่น type Age int)
type Queue[T any] struct{ items []T }
func (q *Queue[T]) Push(x T) { q.items = append(q.items, x) }
func (q *Queue[T]) Pop() (T, bool) {
if len(q.items) == 0 {
var zero T
return zero, false
}
x := q.items[0]
q.items = q.items[1:]
return x, true
}any + เทสต์ก่อน ค่อยตีกรอบ constraint ทีหลังcomparable เมื่อต้องการ == ใช้ ~ เมื่อรับ type พื้นฐานที่ตั้งชื่อใหม่type Number interface{...}) อ่านง่ายกว่าเขียนยาวทุก funcKeys(m map[K]V) []K ดึง keys ออกมาSet[T comparable] ด้วย map แล้วเทสต์ add/has