這是一個建立於
的文章,其中的資訊可能已經有所發展或是發生改變。
package mainimport ( "fmt")type Pointer struct { x string}func (this *Pointer) PrintX() { fmt.Printf("X:%s\n", this.x)}func (this *Pointer) SetX(str string) { this.x = str }type Value struct { x string}func (this Value) PrintX() { fmt.Printf("X:%s\n", this.x)}func (this Value) SetX(str string) { this.x = str }func main() { p1 := Pointer{x: "Pointer"} p1.PrintX() p1.SetX("Pointer1") p1.PrintX() p2 := &Pointer{} p2.PrintX() p2.SetX("Pointer2") p2.PrintX() p3 := Value{x: "Value"} p3.PrintX() p3.SetX("Value1") p3.PrintX() p4 := &Value{x: "value"} p4.PrintX() p4.SetX("Value2") p4.PrintX()}
運行結果:
X:PointerX:Pointer1X:X:Pointer2X:ValueX:ValueX:valueX:value
說明:1 無論是T*作為receiver還是T類型作為接受者,都可以用執行個體、或者執行個體的指標調用函數,但是T*作為接受者將改變receiver的內容,而T類型改變的是副本,原始對象不會改變。
type Type struct {}type PType struct {}type Inter interface { post()}// 接收者非指標func (t Type) post() {}// 接收者是指標func (t *PType) post() {}func test() { var it Inter //var it *Inter //介面不能定義為指標 pty := &Type{} it = ty // 將變數賦值給介面,OK it.post() // 介面調用方法,OK, receiver 是T ty := Type{} it = pty // 把指標變數賦值給介面,OK it.post() // 介面調用方法,OK, receiver 是T pty2 := &PType{} it = pty2 // 把指標變數賦值給介面,OK it.post() // 介面調用方法,OK, receiver 是*T //ty2 := PType{} //it = ty2 // 將變數賦值給介面,error //it.post() // 介面調用方法,error, receiver 必須是T,而不能是T}
詳細代碼:http://play.golang.org/p/KG8-Qb7gqM
為什麼編譯器不考慮我們的值是實現該介面的類型?介面的調用規則是建立在這些方法的接受者和介面如何被調用的基礎上。下面的是語言規範裡定義的規則,這些規則用來說明是否我們一個類型的值或者指標實現了該介面:
- 類型
*T 的可調用方法集包含接受者為 *T 或 T 的所有方法集
這條規則說的是如果我們用來調用特定介面方法的介面變數是一個指標類型,那麼方法的接受者可以是實值型別也可以是指標類型。顯然我們的例子不符合該規則,因為我們傳入 SendNotification 函數的介面變數是一個實值型別。
- 類型
T 的可調用方法集包含接受者為 T 的所有方法
這條規則說的是如果我們用來調用特定介面方法的介面變數是一個實值型別,那麼方法的接受者必須也是實值型別該方法才可以被調用。顯然我們的例子也不符合這條規則,因為我們 Notify 方法的接受者是一個指標類型。
語言規範裡只有這兩條規則,我通過這兩條規則得出了符合我們例子的規則:
- 類型
T 的可調用方法集不包含接受者為 *T 的方法
Interface也是參考型別。