DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on

ลองเขียน Must ฟังก์ชันในแบบ generic ของ Go

#go

หลังจากที่ Proposal เรื่อง Generic (Type Parameters) https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md ผ่านแล้ว อีกประมาณ 1 ปีก็จะออกมาให้ใช้ แต่ในระหว่างนี้เราก็ลองเล่นจาก branch dev.go2go ได้ก็เลยได้หัดคิดว่าโค้ดแบบไหนที่ก่อนหน้านี้ที่เราใช้บ่อยๆ สามารถเอามาเรื่อง generic มาปรับปรุงได้ วันนี้เลยยกฟังก์ชัน Must ที่เราเห็นบ่อยๆในหลายๆ package มาลองเขียนด้วย generic ดู

ตัวอย่างเช่นใน package html/template จะมีฟังก์ชัน Must หน้าตาแบบนี้อยู่

func Must(t *Template, err error) *Template
Enter fullscreen mode Exit fullscreen mode

ใน document เขียนบอกเอาไว้ว่า

Must is a helper that wraps a call to a function returning (*Template, error) and panics if the error is non-nil. It is intended for use in variable initializations such as

var t = template.Must(template.New("name").Parse("html"))
Enter fullscreen mode Exit fullscreen mode

จะเห็นว่ามันก็เป็นฟังก์ชันที่รับผลลัพธ์จากการเรียกฟังก์ชันที่ return (*Template, error) แล้วเช็คว่าถ้ามี error แล้วจะ panic ถ้าไม่มีก็ได้ *Template กลับออกมาให้นั่นเอง เพื่อทำให้เราไม่ต้องเขียน if แบบนี้เอง

var t, err = template.New("name").Parse("html")
if err != nil {
        panic(err)
}
Enter fullscreen mode Exit fullscreen mode

อีกเหตุผลเพราะว่าเราเขียนแบบนี้ในตอนที่เราเรียกฟังก์ชันแล้วกำหนดค่าให้ตัวแปรใน package scope ไม่ได้ด้วยนั่นเอง

อย่างไรก็ตาม ถ้าเราคิดดีๆจะเห็นว่ามีอีกตั้งหลายครั้งที่เราเรียกฟังก์ชันแล้วได้ผลลัพธ์กลับออกมาพร้อม error เช่นตอนเรียก json.Marshal

b, err := json.Marshal(map[string]string{"msg": "Hello"})
if err != nil {
        panic(err)
}
Enter fullscreen mode Exit fullscreen mode

หรือตอนเรียก strconv.Atoi

num, err := strconv.Atoi("30")
if err != nil {
        panic(err)
}
Enter fullscreen mode Exit fullscreen mode

ซึ่งตอนที่ยังไม่มี generic เราต้องเขียน Must แยกเลยสำหรับแต่ละ type เช่นต้องมี Must([]byte, error) สำหรับเคส json.Mashal และ Must(int, error) สำหรับเคส strconv.Atoi

เขียน Must แบบ Generic

ทีนี้เมื่อไหร่ก็ตามที่ Go รองรับ generic แล้วเราสามารถเขียน Must แค่รอบเดียวรองรับทั้ง 3 กรณีด้านบนได้เลยแบบนี้

func Must[T any](v T, err error) T {
    if err != nil {
        panic(err)
    }
    return v
}
Enter fullscreen mode Exit fullscreen mode

คือเรากำหนด type parameter [T any] แล้วเอา type T ไปใช้เป็น parameter แรก แทนที่จะกำหนด type เจาะจงเองแบบก่อนหน้านี้

ทำให้เราใช้ func Must[T any](v T, err error) T ที่เขียนแค่ครั้งเดียวนี้ได้กับที่ 3 กรณีด้านบนแบบนี้

var t = Must(template.New("name").Parse("html"))
var b = Must(json.Marshal(map[string]string{"msg": "Hello"}))
var num = Must(strconv.Atoi("30"))
Enter fullscreen mode Exit fullscreen mode

ขอฝาก Buy Me a Coffee

สำหรับท่านใดที่อ่านแล้วชอบโพสต์ต่างๆของผมที่นี่ ต้องการสนับสนุนค่ากาแฟเล็กๆน้อยๆ สามารถสนับสนุนผมได้ผ่านทาง Buy Me a Coffee คลิ๊กที่รูปด้านล่างนี้ได้เลยครับ

Buy Me A Coffee

ส่วนท่านใดไม่สะดวกใช้บัตรเครดิต หรือ Paypal สามารถสนับสนุนผมได้ผ่านทาง PromptPay โดยดู QR Code ได้จากโพสต์ที่พินเอาไว้ได้ที่ Page DevDose ครับ https://web.facebook.com/devdoseth

ขอบคุณครับ 🙏

Top comments (0)