Go 專欄|說說方法
最近又搬家了,已經(jīng)記不清這是第幾次搬家了。搬到了公司附近,走路十分鐘,以后加班可方便了。
這一篇來說一說方法,方法可以看作是某種特定類型的函數(shù),是 Go 面向?qū)ο缶幊痰牡谝徊健S煤梅椒ǎ邆涿嫦驅(qū)ο缶幊趟枷胧顷P(guān)鍵。
聲明
方法的聲明和函數(shù)類似,他們的區(qū)別是:方法在定義的時(shí)候,會(huì)在 func 和方法名之間增加一個(gè)參數(shù),這個(gè)參數(shù)就是接收者,這樣我們定義的這個(gè)方法就和接收者綁定在了一起,稱之為這個(gè)接收者的方法。
type Person struct {
name string
}
func (p Person) String() string {
return "person name is " + p.name
}
func 和方法名之間增加的參數(shù) (p Person) 就是接收者。現(xiàn)在我們說,類型 Person 有了一個(gè) String 方法。
調(diào)用方法非常簡(jiǎn)單,使用類型的變量和 . 操作符進(jìn)行調(diào)用即可。
p := Person{name: "zhangsan"}
// 調(diào)用方法
fmt.Println(p.String()) // person name is zhangsan
值語義和引用語義
Go 語言里有兩種類型的接收者:值接收者和指針接收者。
使用值類型接收者定義的方法,在調(diào)用的時(shí)候,使用的其實(shí)是值接收者的一個(gè)副本,所以對(duì)該值的任何操作,不會(huì)影響原來的類型變量。
func main() {
p := Person{name: "zhangsan"}
// 調(diào)用方法
fmt.Println(p.String()) // person name is zhangsan
// 值接收者
p.Modify()
fmt.Println(p.String()) // person name is zhangsan
}
// 值接收者
func (p Person) Modify() {
p.name = "lisi"
}
接下來再看一下使用指針接收者的效果:
func main() {
p := Person{name: "zhangsan"}
// 調(diào)用方法
fmt.Println(p.String()) // person name is zhangsan
// 指針接收者
p.ModifyP()
fmt.Println(p.String()) // person name is lisi
}
// 指針接收者
func (p *Person) ModifyP() {
p.name = "lisi"
}
可以看到,改變了原始值,其實(shí)這一點(diǎn)和函數(shù)傳參是一樣的。
有沒有發(fā)現(xiàn),我們?cè)谡{(diào)用指針接收者方法的時(shí)候,使用的也是一個(gè)值的變量,并不是一個(gè)指針,正常來說應(yīng)該這么寫:
(&p).ModifyP()
fmt.Println(p.String())
同樣的,如果是一個(gè)值接收者的方法,使用指針也是可以調(diào)用的:
(&p).Modify()
fmt.Println(p.String())
原因是編譯器幫我們自動(dòng)轉(zhuǎn)義了,這一點(diǎn)大大的方便了我們開發(fā)者。
方法變量和表達(dá)式
上文中已經(jīng)介紹了一種調(diào)用方法,直接使用 . 操作符,比如:p.String()。
接下來再介紹兩種調(diào)用方法:
方法變量
p.Add 可以賦值給一個(gè)方法變量,它相當(dāng)于一個(gè)函數(shù),把方法綁定到一個(gè)接收者上。然后函數(shù)只需要提供實(shí)參而不需要提供接收者即可調(diào)用。
type Point struct {
x, y int
}
func main() {
// 方法變量
p1 := Point{1, 2}
q1 := Point{3, 4}
f := p1.Add
fmt.Println(f(q1)) // {4 6}
}
func (p Point) Add(q Point) Point {
return Point{p.x + q.x, p.y + q.y}
}
方法表達(dá)式
方法表達(dá)式寫成 T.f 或者 (*T).f,其中 T 是類型,是一種函數(shù)變量。
因?yàn)檎{(diào)用方法必須要提供接收者,這種方法相當(dāng)于把接收者替換成了函數(shù)的第一個(gè)形參,因此它可以像函數(shù)一樣調(diào)用。
// 方法表達(dá)式
f1 := Point.Add
fmt.Println(f1(p1, q1)) // {4 6}
總結(jié)
本文主要學(xué)習(xí)了 Go 的方法,方法的聲明和函數(shù)類似,他們的區(qū)別是:方法在定義的時(shí)候,會(huì)在 func 和方法名之間增加一個(gè)參數(shù),這個(gè)參數(shù)就是接收者。
接收者有兩種類型:值接收者和指針接收者。不管是使用值接收者,還是指針接收者,一定要搞清楚類型的本質(zhì):對(duì)類型進(jìn)行操作的時(shí)候,是要改變當(dāng)前值,還是要?jiǎng)?chuàng)建一個(gè)新值進(jìn)行返回?這些就可以決定我們是采用值傳遞,還是指針傳遞。
最后就是方法的調(diào)用,可以直接使用 . 操作符調(diào)用,還可以使用方法變量和方法表達(dá)式。
只有基于面向?qū)ο缶幊趟枷耄拍苁褂煤梅椒āT诤竺嬉獙W(xué)習(xí)的接口中,方法還有更多的應(yīng)用。
文章中的腦圖和源碼都上傳到了 GitHub,有需要的同學(xué)可自行下載。
地址: https://github.com/yongxinz/gopher/tree/main/sc
關(guān)注公眾號(hào) AlwaysBeta,回復(fù)「goebook」領(lǐng)取 Go 編程經(jīng)典書籍。
Go 專欄文章列表:
