前言
在前面的文章中,介紹了 Go 函數的聲明,函數的幾種形式如匿名函數、閉包、基於函數的自定義類型和函數參數詳解等,而本文將對方法進行介紹,方法的本質就是函數,介紹方法的同時也會順帶對比其與函數的不同之處。
方法
在 Go 中,我們可以為任何的數據類型定義方法(指針或接口除外),現在讓我們看一看方法的聲明和組成部分以及與函數有什麼不同之處。
type Person struct {
age int
}
func (p *Person) SetAge(age int) error {
if age < 0 {
return errors.New("年齡不能小於 0 ")
}
p.age = age
return nil
}
上述代碼定義了一個結構體 Person,此結構體包含一個 age 屬性,一個 SetAge 方法,此方法只作用於 Person 結構體。我們可以看到,該方法包含六部分,分別為:
- 1、關鍵字
聲明方法時,必須以func關鍵字開頭,還記得函數的聲明嗎,也是以這個關鍵字開頭。 - 2、
receiver部分
(p *Person)這部分,在Go中稱為receiver部分,裏面的參數稱為receiver參數,相比於函數,方法與其的聲明區別就在於多了這一部分。 - 3、方法名。
Go推薦使用駝峯命名的方式,和變量的命名規則一樣,首字母大寫的方法名可以在包外訪問,小寫的只能在包內訪問。 - 4、參數列表
參數列表中聲明瞭在方法體裏所使用到的變量。參數列表位於方法名後面,用括號包裹着,多個參數使用逗號分隔開。 - 5、返回值列表
返回值為函數執行後的一個結果,上述代碼只有一個返回值,如果有多個返回值,需要用括號包裹着,返回值之間用逗號分隔開。 - 6、方法體
大括號內就是方法體,存放着方法的具體實現。
方法的調用
通過 變量.方法名(參數) 的方式對方法進行調用。例如:
import (
"errors"
"fmt"
)
type Person struct {
age int
}
func (p *Person) SetAge(age int) error {
if age < 0 {
return errors.New("年齡不能小於 0 ")
}
p.age = age
return nil
}
func main() {
person := Person{}
err := person.SetAge(18)
if err != nil {
return
}
fmt.Println(person.age) // 18
}
創建一個 person 變量,然後調用 SetAge 函數。
Receiver 參數類型的選擇
在 Receiver 部分,我們可以綁定值類型,也可以綁定指針類型,這兩種類型什麼時候使用呢?
-
如果方法體裏不涉及到修改結構體變量的屬性值,使用值類型
type Person struct { age int } func (p Person) GetAge() int { return p.age }對於
GetAge方法,作用是返回年齡,沒有涉及到修改年齡的操作,因此receiver部分,選擇Person類型就可以。 -
如果方法體裏有修改結構體變量的屬性值的操作,使用指針類型
type Person struct { age int } func (p *Person) SetAge(age int) error { if age < 0 { return errors.New("年齡不能小於 0 ") } p.age = age return nil }SetAge涉及到對結構體屬性值修改的操作,因此receiver部分使用指針類型,通過指針,可以對所指向地址的變量進行修改操作。
方法的約束
Go 對方法聲明的位置是有約束的,我們不能跨越包去聲明一個類型的方法,根據這個特點我們可以發現:
-
不能為基本數據類型聲明方法
因為基本數據類型所定義的位置,是不在我們所編碼的包裏面的。
-
不能跨越包為其他包的類型聲明方法
這個是
Go的所規定的的。
小結
本文介紹了 Go 方法的聲明方式、組成部分和其與函數的不同點,同時指出Receiver 參數類型在不同場景下的選擇,最後介紹了 Go 對方法約束的體現。
本文參與了SegmentFault 思否寫作挑戰賽活動,歡迎正在閲讀的你也加入。