ลองใช้ Generics Type ที่จะออกมาใน Go 1.18 (beta)

Sippakorn Raksakiart
Wisesight Thailand
Published in
2 min readJan 29, 2022

--

TL;DR

Generics type ใน Golang จะออกใน version 1.18 นี้จะช่วยให้ Developer ลดการสร้างฟังชั่นซ้ำซ้อนและสามารถสร้างฟังชั่นเดียวที่สามารถทำงานได้กับหลายๆ types ได้เลย อ่านเพิ่มเติม

Generics Type คืออะไร

ในภาษา static type อย่าง Golang เราจำเป็นจะต้องกำดหมด type ให้กับทุกๆสิ่งอย่างเช่น เราจะทำ function สำหรับบวกค่าใน array เราก็ต้องรู้ก่อนว่า element ใน array นั้นเป็นอะไร ยกตัวอย่าง code

จากตัวอย่างก็จะเห็นว่าการทำงานของฟังชั่น SumInt และ SumFloat แต่เราต้องทำออกมา 2 ฟังชั่นเพราะว่าเราจำเป็นต้องกำหนด type ที่แตกต่างกันให้ทั้ง 2 ฟังชั่นนี้ แต่ถ้าเราเขียนภาษาที่เป็น dynamic type อย่าง Javascript จะเป็นประมาณนี้

จากตรงนี้จะเห็นว่า code ของ javascript จะเหลือเพียงฟังชั่นเดียวเท่านั้นในขณะที่ Golang จะมี 2 ฟังชั่นตาม type ที่เราต้องการใช้ ซึ่ง Generics type ใน Go 1.18 จะมาแก้ปัญหานี้ให้เรา

Install Go 1.18beta1

ก่อนอื่นเราต้องทำการลง Go 1.18 ตัว beta ในเครื่องของเราก่อน โดยใช้คำสั่งนี้

เริ่มกันเลย

จาก Code ข้างบนจะมีอยู่ทั้งหมด 3 ฟังชั่นหลักๆคือ SumInt, SumFloat และ Sum ซึ่ง SumInt กับ SumFloat ทุกคนคงเข้าใจมันดูอยู่แล้ว สิ่งที่อยากให้ดูคือ Sum เฉยๆเพราะฟังชั่น Sum นี้จะมีสามารถรวมค่าได้ทั้ง float32 และ int เราลองมาดู Syntax ของฟังชั่น Sum กัน

func Sum[V float32 | int] (a []V) V {}

จาก Code ตอนเรา define ฟังชั่นจะมีส่วนที่เราไม่คุ้นเคยมาก่อนใน Go สิ่งที่เรียกว่า Type parameter โดยส่วนของ type parameter นี้เราอยู่ในเครื่อง Brackets ซึ่ง type parameter จะเป็นตัวกำหนดว่าฟังชั่นนี้จะรับ Type ได้ 2 แบบนะคือ int และ float32 ซึ่งตรงนี้เราจะเรียกมันว่า Type constraint พอถึงตรงนี้เราน่าจะเจอเครื่องหมายที่ไม่คุ้นเคยอีกตัวคือ | หรือหลายๆคนอาจจะเรียกมันว่าเครื่องหมาย pipe ซึ่งในกรณีในเราใช้มันการทำทำ union type หรือบอกกับ Go compiler ว่า type paremeter V นี้จะเป็นได้ทั้ง type int หรือ float32 นะ

สร้าง Type ใหม่โดยใช้ Union type

จาก code ข้างบนจะเห็นว่าหากเรามีฟังชั่นแนวนั้นเพิ่มขึ้นมาเราก็จะต้องใส่ type paremeter แบบนี้ในทุกฟังชั่น

func Sum[V float32 | int] (a []V) V {}
func Multiply[V float32 | int] (a []V) V {}

เราเลยจะทำการ Refactor มันโดยการเพิ่ม type ใหม่เข้าไปโดยให้ชื่อว่า Number โดย code จะเป็นตามนี้

The Any Constraints

ใน Golang 1.18 ยังจะมี Constraints อื่นมาให้เราใช้อีก ซึ่งตัวที่เราจะพูดถึงคือ any โดย any Constraints นี้จะเป็นตัวบอกว่าฟังชั่นของเรานั้นรับได้ทุก type นะ แต่ตอนเรา compile ตัว Golang compiler จะมีการเช็คก่อนว่าฟังชั่นที่เรา implement มานั้นสามารถใช้ได้กับทุก type จริงๆไหม โดยตัวอย่าง code จะเป็นประมาณนี้ครับ

หาเราลองเพิ่ม code ในฟังชั่น AddEmoji นิดหน่อยโดยการเรียกใช้ operator + ในฟังชั่นนี้แบบนี้

return fmt.Sprintf("%v%s", v + v, "💩")

แล้วหลังจากนั้นลอง compile ใหม่

# command-line-arguments
./main.go:50:29: invalid operation: operator + not defined on v (variable of type T constrained by any)

เราจะได้ error หน้าตาแบบนี้ ถึงแม้ว่าตอนเราเรียกใช้เราจะส่ง string หรือ int เข้าไปแต่นั้นก็ guarantee ไม่ได้ว่าทุกตัวแปลที่จะถูกเรียกใช้ผ่านฟังชั่นนี้จะสามารถเรียกใช้ operator + ได้ดังนั้น compiler เลยไม่อณุญาติให้เรา compile code นี้และแจ้ง error ออกมา

The Comparable constraint

ถัดมาเราจะลองใช้ comparable constraint กัน โดยเราจะทำฟังชั่นที่ใช้ compare ค่าสองค่าถ้าเท่ากันก็จะคืนค่าเป็น Boolean ออกไป

ซึ่งจาก code นี้พอเรา compile ออกมาก็จะ Error ออกมาเนื่องจากหากเราใช้ any ตัว Go จะไม่อนุญาติให้ใช้ operator == เพราะบาง type ก็ไม่สามารถใช้ ==, !=, >, < ได้ ดังนั้นเราจะทำการแก้โค๊ดนี้ใหม่โดยเปลี่ยนจาก any เป็น comparable

จาก code ข้างต้นเราก็จะทำการ compile code ของเราได้แล้ว

แต่หากเราลองเพิ่ม code นิดหน่อย โดยการส่งตัวแปลที่ไม่สามารถ compare ได้อย่าง slice of string เข้าไปล่ะจะเป็นยังไง

พอเราลอง compile code นี้ ผลลัพธ์ที่ได้ก็จะเป็น compile error ดังนี้

# command-line-arguments
./main.go:24:50: []string does not implement comparable

Conclusion

สรุปจะที่ผมลองเล่นมาก็คิดว่าการมาของ Go 1.18 ที่มาพร้อม Generics type จะช่วยให้เราลดจำนวน code ลงได้เยอะ และ จะช่วยให้ code ของเรา re-use ได้มากขึ้น ซึ่งก็ยังคงความเป็นภาษาที่ type safe อยู่

และผมหวังว่าบทความนี้จะช่วยให้เพื่อน Golang Developer สำหรับการใช้งาน Generics type ใน Golang ได้นะครับ หากผิดผลาดตรงไหนแจ้งได้เลยนะครับ และสามารถอ่านเพิ่มเติมได้ใน Reference ข้างล่างเลยครับ

Reference

Tutorial: Getting started with generics — The Go Programming Language

Generics in Go — Bitfield Consulting

--

--