Go語言 方法調(diào)用

2018-07-25 16:01 更新

普通的函數(shù)調(diào)用

普通的函數(shù)調(diào)用跟C語言中的調(diào)用方式基本上是一樣的,除了多值返回的一些細(xì)微區(qū)別,見前面章節(jié)。

對象的方法調(diào)用

根據(jù)Go語言文檔,對象的方法調(diào)用相當(dāng)于普通函數(shù)調(diào)用的一個語法糖衣。

type T struct {
    a int
}
func (tv  T) Mv(a int) int         { return 0 }  // value receiver
func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver

var t T

表達(dá)式

T.Mv

得到一個函數(shù),這個函數(shù)等價于Mv但是帶一個顯示的接收者作為第一個參數(shù),也就是

func(tv T, a int) int

下面這些調(diào)用是等價的:

t.Mv(7)
T.Mv(t, 7)
(T).Mv(t, 7)
f1 := T.Mv; f1(t, 7)
f2 := (T).Mv; f2(t, 7)

可以看了一下方法調(diào)用用生成的匯編代碼:

type T int
func (t T) f() {
    fmt.Println("hello world!\n")
}

func main() {
    var v T
    v.f()
    return
}

將它進(jìn)行匯編:

go tool 6g -S test.go

得到的匯編代碼是:

0044 (sum.go:15) TEXT    main+0(SB),$8-0
0045 (sum.go:15) FUNCDATA $0,gcargs·1+0(SB)
0046 (sum.go:15) FUNCDATA $1,gclocals·1+0(SB)
0047 (sum.go:16) MOVQ    $0,AX
0048 (sum.go:17) MOVQ    AX,(SP)
0049 (sum.go:17) CALL    ,T.f+0(SB)
0050 (sum.go:18) RET     ,

從這段匯編代碼中可以看出,方法調(diào)用跟普通函數(shù)調(diào)用完全沒有區(qū)別,這里就是把v作為第一個參數(shù)調(diào)用函數(shù)T.f()。

組合對象的方法調(diào)用

在Go中沒有繼承,但是有結(jié)構(gòu)體嵌入的概念。將一個帶方法的類型匿名嵌入到另一個結(jié)構(gòu)體中,則這個結(jié)構(gòu)體也會擁有嵌入的類型的方法。

這個功能是如何實現(xiàn)的呢?其實很簡單。當(dāng)一個類型被匿名嵌入結(jié)構(gòu)體時,它的方法表會被拷貝到嵌入結(jié)構(gòu)體的Type的方法表中。這個過程也是在編譯時就可以完成的。對組合對象的方法調(diào)用同樣也僅僅是普通函數(shù)調(diào)用的語法糖衣。

接口的方法調(diào)用

接口的方法調(diào)用跟上述情況略有不同,不同之處在于它是根據(jù)接口中的方法表得到對應(yīng)的函數(shù)指針,然后調(diào)用的,而前面是直接調(diào)用的函數(shù)地址。

對象的方法調(diào)用,等價于普通函數(shù)調(diào)用,函數(shù)地址是在編譯時就可以確定的。而接口的方法調(diào)用,函數(shù)地址要在運行時才能確定。將具體值賦值給接口時,會將Type中的方法表復(fù)制到接口的方法表中,然后接口方法的函數(shù)地址才會確定下來。因此,接口的方法調(diào)用的代價比普通函數(shù)調(diào)用和對象的方法調(diào)用略高,多了幾條指令。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號