Higher Order Function ใน Go
ในภาษา Go การเขียน Higher-Order Functions (HOF) เริ่มมีความน่าสนใจและใช้งานได้กว้างขวางขึ้นมากหลังจากที่มี Generics (Go 1.18+) เข้ามา เพราะเราไม่ต้องเขียนฟังก์ชันแยกสำหรับทุก Type อีกต่อไป
Higher-Order Functions ใน Go: ยกระดับโค้ดให้ยืดหยุ่นด้วย Generics
ในภาษา Go ฟังก์ชันถือเป็น "First-class citizen" หมายความว่าเราสามารถเก็บฟังก์ชันไว้ในตัวแปร, ส่งเข้าไปในฟังก์ชันอื่น หรือคืนค่าฟังก์ชันออกมาได้ รูปแบบนี้เรียกว่า Higher-Order Functions (HOF) ซึ่งเป็นหัวใจสำคัญของการเขียนโค้ดที่ประกอบร่างได้ (Composable) และทดสอบง่าย (Testable) เรามาดูกันว่าเราสามารถทำ HOF ได้กี่แบบ
ตัวอย่างที่ 1: ฟังก์ชั่นที่รับฟังก์ชั่น
func Apply[T any](f func(T) T, x T) T {
return f(x)
}
func pure(x int) int {
return x * 2
}
func TestApply() {
result := Apply(pure, 5)
println(result) // Output: 10
}ตรงนี้มีเรื่องน่าสนใจคือ เราสามารถเอาฟังก์ชั่นไปใส่ไว้ในตัวแปรไว้ก่อนได้ไหมแล้วค่อยส่งไปใน function ที่รับ function
ตัวอย่างที่ 2: ตัวแปรที่เป็นฟังก์ชั่น
func TestApply() {
double := func (x int) int {
return x * 2
}
result := Apply(double, 5)
println(result)
}ถึงตรงนี้เราเริ่มเห็นอะไรน่าสนุกละ
ตัวอย่างที่ 3 ฟังก์ชั่นที่รับฟังก์ชั่นเข้ามาแล้ว return ฟังก์ชั่นกลับออกไป
// Example 2: A higher-order function that returns a function
func Compose[T any](f, g func(T) T) func(T) T {
return func(x T) T {
fmt.Println("Composing functions!!!")
return f(g(x))
}
}
func TestCompose() {
double := func(x int) int {
fmt.Println("Doubling!!!")
return x * 2
}
increment := func(x int) int {
fmt.Println("Incrementing!!!")
return x + 1
}
composed := Compose(double, increment)
result := composed
fmt.Println(result)// 0xa6210
fmt.Println(result(5))//Output: 12 (double(increment(5)) = double(6) = 12)
}สำหรับผมจุดนี้เป็นจุดที่น่าสนใจและเป็นจุดเชื่อมที่สำคัญมาก เราจะเห็นว่า composed เป็นตัวแปรที่มี type เป็น function และใน function ทั้งสองตัวมี effect ที่ถูกทดเอาไว้แต่ยังไม่ทำงานจนกว่าจะจะสั่งให้มันทำงาน !!!!!! และก่อนนั้นเราสามารถ reassign มันไปมาได้ เราจะใช้สิ่งนี้สร้างของที่ ทรงพลังมากในการคิดแบบ functional (ตอนถัดๆไป)