結構可以定義同類型的資料,而同類型的資料通常又會有同類型的行為。因為 Go 有 Anonymous Function ,有寫過 Javascript 可能第一個想到的解法是這樣:
package main
import "fmt"
type People struct {
name string
age int
Hello func(other People) string
}
func main() {
var miles People
other := People{name: `Someone`}
miles = People{`Miles`, 18, func(other People) string {
return `Hi! ` + other.name + `, I am ` + miles.name
}}
fmt.Println(miles.Hello(other)) // Hi! Someone, I am Miles
}
但明顯的缺點是,它需要動態給匿名函式的值,且需要閉包才能取得 miles
變數,這樣一來函式就很難共用,二來得先宣告 miles
,才能把匿名函式指定給 miles
,整個程式會變得有點混亂。
不如,我們把函式定義改一下:
package main
import "fmt"
type People struct {
name string
age int
Hello func(self People, other People) string
}
func main() {
hello := func(self People, other People) string {
return `Hi! ` + other.name + `, I am ` + self.name
}
other := People{name: `Someone`}
miles := People{`Miles`, 18, hello}
fmt.Println(miles.Hello(miles, other)) // Hi! I am Miles
}
第一個傳的值就是結構變數,在函式裡就可以使用 self 取得結構的資料。這做法有點類似 Python 定義類別裡的 self
,只是需要自己手動傳值。
事實上 Go 有提供更好的寫法:
package main
import (
"fmt"
)
type People struct {
name string
age int
}
func (people People) Hello(other People) string {
return `Hi! ` + other.name + `, I am ` + people.name
}
func main() {
other := People{name: `Someone`}
miles := People{`Miles`, 18}
fmt.Println(miles.Hello(other)) // Hi! Someone, I am Miles
}
它的概念是定義一個函式 func
,而開頭就宣告這是哪個結構所使用的,以及裡面將會用什麼變數來代表結構本身 (people People)
(傳值或傳址都可以),後面就跟平常定義函數一樣。
這樣的寫法,就會把 Hello
函式跟 People
綁定在一起,用起來就會非常像物件導向的寫法了。