1. 程式人生 > >Go語言之方法詳解

Go語言之方法詳解

go語言 方法

方法是與對象實例綁定的特殊函數。

用於維護和展示對象自身的狀態。對象是內斂的。普通函數則專註與算法流程,通過接受參數來完成特定的邏輯運算,並返回最終結果,方法是有關聯狀態的,函數通常是沒有的。

方法和函數定義語法區別在於前者實例接受參數,編譯器以此確定方法所屬的類型。在一些語言中盡管沒有定義,但是函數使用了隱式的傳遞this實例參數。

可以為當前包,以及除接口和指針以外的任何類型定義方法。方法同樣不支持重載,receiver參數名沒有限制。不推薦使用this和self。方法可以看做特殊的函數,那麽receiver的類型自然可以是基礎類型或指針。這會關系到調用時對象實例是否被復制。

不可以使用多級指針調用方法。

指針類型的receiver必須是合法指針(包括nil),或能獲取實例地址。


如何選擇方法的接收器類型:

使用T:

1.不需要修改狀態的小對象或者是固定值。

2.引用類型、字符串、函數等指針包裝對象。

使用*T:

1.需要修改實例狀態。

2.大對象使用*T,以減少復制成本。

3.如果包含Mutex等同步字段,用*T,避免因為復制造成鎖操作無效。

4.其他無法確定全部使用*T。


匿名字段:

方法也會有同名遮蔽問題。但是利用這種特性,可以實現類似的覆蓋操作。

方法集:

類型有一個與之相關的方法集,這決定它是否實現某個接口。

類型T方法集合包含所有receiver T方法。

類型*T方法集合包含receiver T + *T方法。

匿名嵌入S,T方法集包含所有receiver S方法。

匿名嵌入*S,T方法集包含所有的receiver S + receiver *S方法。

匿名嵌入S或者*S,*T方法集包含所有receiver S + *S。

表達式:

方法可以分為expression和value兩種方法狀態。

(1)方法表達式:

通過類型引用的方法表達式會被還原成為普通函數樣式,接收器是第一個參數,調用時必須顯式傳參。至於類型,可以是T或者是*T,只要目標方法存在於該類型方法集中即可。

(2)方法值:

基於實例或者是指針引用的方法值,參數簽名不會改變,依舊按照正常方式調用。但是當方法值被賦值給變量或者是作為參數傳遞時,會立即計算並復制該方法執行所需要的接收器對象,與其綁定,以便在稍後執行時,能隱式傳遞接收器對象。

編譯器會為方法值生成一個包裝函數,實現間接調用。至於接收器復制。和閉包的實現方法基本相同,打包成funval,經由DX寄存器傳送。當然,如果目標方法的接收器是指針類型,那麽被復制的僅僅是指針。只要是接收器參數類型正確,使用nil同樣可以執行。

package main


import "fmt"


type N int


func main() {

var number N = 100

result := number.toString()

fmt.Println(result)//d

}


func (number N)toString() string{

return fmt.Sprintf("%s",string(number))

}

運行結果:

d


package main


import "fmt"


type N int


func main() {

var a N = 25

a.value()

a.pointer()

fmt.Printf("a: %p, %v", &a, a)

}

func (n N) value() {

n++

fmt.Printf("v: %p, %v\n", &n, n)

}

func (n *N) pointer() {

(*n)++

fmt.Printf("p: %p, %v\n", n, *n)

}

/*

運行結果:

v: 0xc04204c088, 26

p: 0xc04204c080, 26

a: 0xc04204c080, 2

*/


Go語言之方法詳解