?# 11.6 使用方法集與接口
在第 10.6.3 節(jié)及例子 methodset1.go 中我們看到,作用于變量上的方法實(shí)際上是不區(qū)分變量到底是指針還是值的。當(dāng)碰到接口類型值時(shí),這會(huì)變得有點(diǎn)復(fù)雜,原因是接口變量中存儲(chǔ)的具體值是不可尋址的,幸運(yùn)的是,如果使用不當(dāng)編譯器會(huì)給出錯(cuò)誤??紤]下面的程序:
示例 11.5 methodset2.go:
package main
import (
"fmt"
)
type List []int
func (l List) Len() int {
return len(l)
}
func (l *List) Append(val int) {
*l = append(*l, val)
}
type Appender interface {
Append(int)
}
func CountInto(a Appender, start, end int) {
for i := start; i <= end; i++ {
a.Append(i)
}
}
type Lener interface {
Len() int
}
func LongEnough(l Lener) bool {
return l.Len()*10 > 42
}
func main() {
// A bare value
var lst List
// compiler error:
// cannot use lst (type List) as type Appender in argument to CountInto:
// List does not implement Appender (Append method has pointer receiver)
// CountInto(lst, 1, 10)
if LongEnough(lst) { // VALID:Identical receiver type
fmt.Printf("- lst is long enough\n")
}
// A pointer value
plst := new(List)
CountInto(plst, 1, 10) //VALID:Identical receiver type
if LongEnough(plst) {
// VALID: a *List can be dereferenced for the receiver
fmt.Printf("- plst is long enough\n")
}
}
討論
在 lst
上調(diào)用 CountInto
時(shí)會(huì)導(dǎo)致一個(gè)編譯器錯(cuò)誤,因?yàn)?CountInto
需要一個(gè) Appender
,而它的方法 Append
只定義在指針上。 在 lst
上調(diào)用 LongEnough
是可以的,因?yàn)?Len
定義在值上。
在 plst
上調(diào)用 CountInto
是可以的,因?yàn)?CountInto
需要一個(gè) Appender
,并且它的方法 Append
定義在指針上。 在 plst
上調(diào)用 LongEnough
也是可以的,因?yàn)橹羔槙?huì)被自動(dòng)解引用。
總結(jié)
在接口上調(diào)用方法時(shí),必須有和方法定義時(shí)相同的接收者類型或者是可以從具體類型 P
直接可以辨識(shí)的:
將一個(gè)值賦值給一個(gè)接口時(shí),編譯器會(huì)確保所有可能的接口方法都可以在此值上被調(diào)用,因此不正確的賦值在編譯期就會(huì)失敗。
譯注
Go 語(yǔ)言規(guī)范定義了接口方法集的調(diào)用規(guī)則: