📅 เขียนเมื่อ: กันยายน 2026 | Go 1.27
⚠️ API/เวอร์ชันอาจเปลี่ยนแปลง — ตรวจสอบเอกสารล่าสุดก่อนใช้งาน
ปลายเดือนสิงหาคมที่ผ่านมา บัญชีทางการของ GoLand โพสต์คลิปวิดีโอสั้น ๆ ความยาว 36 วินาที ของ Robert Griesemer (หนึ่งในผู้ร่วมสร้างภาษา Go) เล่าเบื้องหลังของฟีเจอร์หนึ่ง พร้อมคำถามชวนคิดว่า:
"ทำไมทีม Go ถึงข้าม generic methods ตอน 1.18 แล้วกลับมาใส่ใน 1.27?"
คำตอบสั้น ๆ คือมันเป็นเรื่องราวยาว 5 ปี ที่เริ่มจากทีมออกแบบบอกว่า "ทำไม่ได้/ไม่น่าจะทำ" ไปจนถึงวันที่ community ผลักดันจนฟีเจอร์นี้กลายเป็นจริง — บทความนี้จะเล่าเรื่องนั้นให้ฟัง พร้อมอธิบายว่า generic methods คืออะไร และทำไมมันถึงสำคัญ
เกริ่น: Go 1.18 เปิดตัว generics แต่ทิ้งช่องว่างไว้
ย้อนไป กุมภาพันธ์ 2022 — Go 1.18 เปิดตัว generics (type parameters) ซึ่งถือเป็นการเปลี่ยนแปลงภาษา Go ครั้งใหญ่ที่สุดครั้งหนึ่ง หลังรอคอยกันมานานหลายปี
แต่ในดีไซน์นั้นมีข้อจำกัดหนึ่งที่หลายคนสังเกตเห็นทันที: method ประกาศ type parameters ของตัวเองไม่ได้
แปลง่าย ๆ ว่า generics ตอน 1.18 ใช้ได้กับ
- ฟังก์ชันระดับ package:
func Max[T cmp.Ordered](a, b T) T - และ type:
type List[T any] struct { ... }
แต่ใช้กับ method ไม่ได้ — method ที่ผูกกับ receiver จะรับ type parameters เพิ่มเองไม่ได้ ต้องใช้ type parameters ของ type ต้นทางเท่านั้น
Generic methods คืออะไร
ขอทำให้เห็นภาพด้วยตัวอย่างคลาสสิก — สมมติมี List[T] แล้วอยากได้ method .Map ที่แปลง element จาก type T เป็น type U
ก่อน Go 1.27 เราทำแบบนี้ได้อย่างเดียว (เป็นฟังก์ชันระดับ package):
func Map[T, U any](l *List[T], f func(T) U) *List[U] {
result := &List[U]{}
for _, item := range l.items {
result.items = append(result.items, f(item))
}
return result
}
// ใช้แบบนี้ — อ่านแล้วต้องไล่จากขวาไปซ้าย
mapped := Map(list, func(n int) string { return strconv.Itoa(n) })
ส่วนแบบที่หลายคนอยากได้ — เรียกเป็น method ต่อท้ายแบบ chain อย่างนี้ — เขียนไม่ได้:
// ❌ ก่อน Go 1.27: method ประกาศ type parameter U เองไม่ได้
func (l *List[T]) Map[U any](f func(T) U) *List[U] { ... }
Go 1.27 ทำให้แบบหลังนี้เป็นจริงแล้ว — method ประกาศ type parameters ของตัวเองได้ ซึ่งทำให้เขียน DSL และ chain ของ method ได้สะอาดขึ้นมาก (ตัวอย่างจริงใน standard library คือ math/rand/v2 ที่เปลี่ยนจาก generic function N[Int intType](Int) Int มาเป็น generic method (*Rand).N[Int intType](Int) Int)
ทำไมตอน 1.18 ถึงข้ามไป
เหตุผลหลักคือความซับซ้อนในการ implement ไม่ใช่ "ไม่อยากทำ"
- เรื่อง dictionary — Go implement generics ด้วยการส่ง "type dictionary" ตามไปกับค่า การให้ method มี type parameters เอง แปลว่า dictionary ต้องถูกส่งผ่าน method value และ interface ซึ่งซับซ้อนกว่าฟังก์ชันธรรมดามาก
- คำถามเรื่อง interface — ข้อถกเถียงที่ค้างมานาน: ถ้า method มี type parameters แล้วมันจะ "implement interface" ได้ไหม? ถ้าได้ จะตรวจ type ยังไง? ถ้าไม่ได้ แล้วทำไมไม่ใช้ฟังก์ชันธรรมดาแทน?
ประเด็นนี้ชัดเจนจากคอมเมนต์ของ Ian Lance Taylor (ผู้ร่วมออกแบบ generics) ใน proposal วันที่ 21 ตุลาคม 2021:
"This proposal is a non-starter unless someone can explain how to implement it."
และที่น่าจำคือตอนนั้น Go FAQ ถึงกับเขียนไว้ว่า:
"We do not anticipate that Go will ever add generic methods."
แล้ว community เปลี่ยนเกมยังไง
แต่สิ่งที่ทีมออกแบบประเมินไว้ต่ำไป คือแรงกดดันจากคนใช้งาน
proposal ตัวนี้ (golang/go #49085) ถูกเปิดไว้ตั้งแต่วันที่ 20 ตุลาคม 2021 — สองสามเดือนก่อน Go 1.18 จะออกด้วยซ้ำ — และสะสมความเห็นจากชุมชนไปเรื่อย ๆ จนมี 👍 กว่า 906 ครั้ง (ตัวเลขที่สูงมากสำหรับ proposal ภาษา Go)
use case ที่คนเอามาโชว์กันส่วนใหญ่เป็นเรื่องจริงจัง ไม่ใช่แค่ "อยากได้":
-
DSL สำหรับ stream processing —
.Map(...).Filter(...)ต่อเป็น chain แบบที่ไลบรารีด้าน data pipeline ใช้กัน -
DSL สำหรับ testing —
Assert(actual).ToBe(expected)อ่านเป็นประโยคได้ -
DSL สำหรับ mocking —
On(obj.Sum).WithArgs(7, 8).ThenReturn(15)
ทั้งหมดนี้เขียนด้วย method chaining ได้สวย แต่ถ้าไม่มี generic methods จะต้องถอยกลับไปเขียนเป็นฟังก์ชันระดับ package ซึ่งอ่านย้อนหลังและอุ้ยอ้ายกว่า
เมื่อเวลาผ่านไป 5 ปี คำตอบของคำถามเชิงเทคนิคก็ค่อย ๆ ชัดขึ้น จนในที่สุด Go 1.27 (สิงหาคม 2026) ก็ประกาศรองรับ generic methods อย่างเป็นทางการ — โดยปิด proposal #49085 เดิมเป็น "duplicate" ของ issue #77273 ที่ implement จริง
นี่คือจังหวะที่ Robert Griesemer เล่าในวิดีโอ — ว่าจุดเปลี่ยนจริง ๆ คือเสียงตอบรับจาก community ที่ยืนกรานว่า use case พวกนี้ "จำเป็น" ไม่ใช่ "ของเล่น"
ข้อจำกัดที่ยังเหลือ (สำคัญ)
อย่าเพิ่งดีใจจนลืมอ่าน footnote ใน release notes — Go 1.27 ระบุชัดว่า:
- method ของ interface ยังประกาศ type parameters ไม่ได้
- และ generic method ไม่สามารถ ไป implement interface method ได้
แปลว่า generic methods ใช้ได้กับ concrete type (struct ฯลฯ) แต่ยังแตะเรื่อง "generic interface method" ไม่ได้ — นี่คือขอบเขตที่ทีม Go ตั้งใจจำกัดไว้ให้ออกแบบต่อได้ในอนาคต
สรุป
เรื่องนี้เป็นกรณีศึกษาที่ดีมากของวิธีที่ Go (ในฐานะภาษา open source) รับมือกับฟีเจอร์ที่ขอเข้ามามาก:
- ตอน 1.18 ทีมออกแบบตัด generic methods ออกอย่างจงใจ เพราะ implement ไม่ลงตัวและคำถามเรื่อง interface ยังค้าง
- ชุมชนเปิด proposal (#49085) ยื่น use case จริง และกด 👍 กันเป็นพัน
- ทีมตั้งท่าไว้ก่อน ("non-starter", FAQ บอก "ไม่มีทาง") แต่ก็ไม่ได้ปิดประตูถาวร
- 5 ปีต่อมา ปมเชิงเทคนิคถูกแก้ได้จริง → Go 1.27 ใส่ generic methods เข้ามา
ข้อคิดสำหรับคนเขียน Go: ฟีเจอร์ที่ทีมเคยบอกว่า "ไม่น่ามี" ก็มีวันเป็นจริงได้ ถ้า use case มัน "จริง" พอ — และตอนนี้ generic methods ก็พร้อมให้ใช้แล้วใน Go 1.27
แหล่งอ้างอิง
- วิดีโอต้นเรื่อง (GoLand / Robert Griesemer) — https://x.com/GoLandIDE/status/2094810876565987652
- Go 1.27 Release Notes (generic methods, issue #77273) — https://go.dev/doc/go1.27
- Proposal #49085: allow type parameters in methods — https://github.com/golang/go/issues/49085
- Type Parameters design doc (no parameterized methods) — https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md
Top comments (0)