?# 11.6 使用方法集與接口
在第 10.6.3 節(jié)及例子 methodset1.go 中我們看到,作用于變量上的方法實際上是不區(qū)分變量到底是指針還是值的。當(dāng)碰到接口類型值時,這會變得有點復(fù)雜,原因是接口變量中存儲的具體值是不可尋址的,幸運的是,如果使用不當(dāng)編譯器會給出錯誤。考慮下面的程序:
示例 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 時會導(dǎo)致一個編譯器錯誤,因為 CountInto 需要一個 Appender,而它的方法 Append 只定義在指針上。 在 lst 上調(diào)用 LongEnough 是可以的,因為 Len 定義在值上。
在 plst 上調(diào)用 CountInto 是可以的,因為 CountInto 需要一個 Appender,并且它的方法 Append 定義在指針上。 在 plst 上調(diào)用 LongEnough 也是可以的,因為指針會被自動解引用。
總結(jié)
在接口上調(diào)用方法時,必須有和方法定義時相同的接收者類型或者是可以從具體類型 P 直接可以辨識的:
將一個值賦值給一個接口時,編譯器會確保所有可能的接口方法都可以在此值上被調(diào)用,因此不正確的賦值在編譯期就會失敗。
譯注
Go 語言規(guī)范定義了接口方法集的調(diào)用規(guī)則: