深入瞭解 Go 語言的方法

方法主要源於 OOP 語言,在傳統面嚮對象語言中 (例如 C++), 我們會用一個“類”來封裝屬於自己的數據和函數,這些類的函數就叫做方法。

雖然 Go 不是經典意義上的面嚮對象語言,但是我們可以在一些接收者(自定義類型,結構體)上定義函數,同理這些接收者的函數在 Go 裏面也叫做方法。

聲明

方法(method)的聲明和函數很相似, 只不過它必須指定接收者,我們先來看個簡單例子:

package main

type T struct{}

func (t T) F()  {}

func main() {
    t := T{}
    t.F()
}

接收者類型不是任意類型
例如:

package main

func (t int64) F()  {}

func main() {
    t := int64(10)
    t.F()
}

當運行以下代碼會得到 cannot define new methods on non-local type int64 類似錯誤信息,我們可以使用自定義類型來解決:

package main

type T int64
func (t T) F()  {}

func main() {
    t := T(10)
    t.F()
}

小結:接收者不是任意類型,它只能爲用關鍵字 type 定義的類型(例如自定義類型,結構體)。

命名衝突

a. 接收者定義的方法名不能重複, 例如:

package main

type T struct{}

func (T) F()         {}
func (T) F(a string) {}

func main() {
    t := T{}
    t.F()
}

運行代碼我們會得到 method redeclared: T.F 類似錯誤。

b. 結構體方法名不能和字段重複,例如:

package main

type T struct{
  F string
}

func (T) F(){}

func main() {
    t := T{}
    t.F()
}

運行代碼我們會得到 : type T has both field and method named F 類似錯誤。

小結: 同一個接收者的方法名不能重複 (沒有重載);如果是結構體,方法名不能和字段重複。

接收者可以同時爲值和指針

在 Go 語言中,方法的接收者可以同時爲值或者指針,例如:

package main

type T struct{}

func (T) F()  {}
func (*T) N() {}

func main() {
    t := T{}
    t.F()
    t.N()

    t1 := &T{} // 指針類型
    t1.F()
    t1.N()
}

可以看到無論值類型 T 還是指針類型 &T 都可以同時訪問 F 和 N 方法。

值和指針作爲接收者的區別

同樣我們先看一段代碼:

package main

import "fmt"

type T struct {
    value int
}

func (m T) StayTheSame() {
    m.value = 3
}

func (m *T) Update() {
    m.value = 3
}

func main() {
    m := T{0}
    fmt.Println(m) // {0}

    m.StayTheSame()
    fmt.Println(m) // {0}

    m.Update()
    fmt.Println(m) // {3}
}

運行代碼輸出結果爲:

{0}
{0}
{3}

小結:值作爲接收者(T) 不會修改結構體值,而指針 *T 可以修改。

總結

可以看到在 Go 語言中方法有一些比較特殊的地方,主要爲以下幾點:

接收者的類型只能爲用關鍵字 type 定義的類型,例如自定義類型,結構體。
同一個接收者的方法名不能重複 (沒有重載),如果是結構體,方法名還不能和字段名重複。
值作爲接收者無法修改其值,如果有更改需求,需要使用指針類型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章