1 回答

TA貢獻1833條經(jīng)驗 獲得超4個贊
這是絆倒的常見點,特別是對于剛接觸更高層次語言背景的人來說。以下是我如何保持直截了當:
首先,讓我們確定Go中的“接收器”(例如“方法”)是什么。就像Python一樣,一個方法實際上與一種類型相連的事實是語法糖??档氯麪栠@個例子:
package main
import "fmt"
type F struct {
i int
}
func (f F)Foo() {
fmt.Println(f.i)
}
func main() {
F.Foo(F{1})
}
盡管可能令人驚訝,但此代碼已編譯并成功打印出預期的 .這是因為當您在類型上調(diào)用接收器時,真正發(fā)生的事情是該類型成為接收器的第一個參數(shù)。1
真的很快,讓我們也回顧一下指針,因為你似乎在評論中倒著說了。因此,需要明確的是:計算機程序中的任何值都存儲在內(nèi)存中,它在內(nèi)存中的地址也是可以存儲在變量中的值。我們將這些變量稱為“指向”值的指針。
如果我給一個函數(shù)一個值,他們只能在其函數(shù)的范圍內(nèi)更改該值。如果該值是內(nèi)存中的地址,則同樣如此。但是,我可以更改該地址的數(shù)據(jù),從而影響具有函數(shù)外部范圍的數(shù)據(jù)。
package main
import "fmt"
func f(i int) { i = i + 2 }
func pf(i *int) { *i = *i + 2 }
var i = 1
func main() {
f(i)
fmt.Println(i)
pf(&i)
fmt.Println(i)
}
打印輸出
1
3
f(i)更改其本地副本,但更改存儲在 中的地址處的數(shù)據(jù)。ipf(&i)i
我為什么經(jīng)歷這一切?因為這就是圍棋中的大多數(shù)接收器都是指針接收器的原因;因為您不想傳遞接收器的副本;您實際希望傳遞接收方的地址,以便它可以在自己的方法中改變自身。
請記住,接收器是語法糖:
func (t *Type)f(arg string)
等效于:
func f(t *Type, arg string)
希望這能清楚地說明為什么指針接收器如此普遍!好了,說到界面方面。
如您所知,接口定義了一組方法。如果類型定義了具有相同簽名的方法,則該類型將滿足該接口。對于值接收器或指針接收器,情況可能如此。
但是,一個類型不能同時具有具有相同名稱的值接收器和指針接收器:
func (t T)F() {}
func (t *T)F() {} //method redeclared: T.F
因此,這意味著類型和指向該類型的指針不能具有相同的接收器;因此,類型或指向類型的指針實現(xiàn)接收器,但不是兩者。這一點很容易被忽視,因為go會自動轉換。所以這工作正常:
type T struct{}
func (t T)F() {}
func (t *T)PF() {}
func main() {
var t T
t.F()
t.PF()
}
在 中,將自動轉換為指針。t.PF()t
但重申一下,類型和指向類型的指針不能同時定義相同的接收器。因此,如果滿足接口 ,則不滿足,反之亦然。TI*T
話雖如此,并且已經(jīng)理解了這一點,很容易想出一個簡單的規(guī)則:當你打算用指針滿足接口時,永遠不要將指針指向接口。
在代碼中,滿足 。所以你可以說你的“真的是*A*A'沒有任何意義。*AIAIA. Thinking of it like this, you can see that taking the address of an IA that is actually an
將它們放在一起,下面是定義兩個接口并鏈接調(diào)用。請注意,雖然指向我的結構的指針可能是滿足接口的值,但我永遠不需要獲取接口的地址。對于 和 接口的使用者來說,它們是類型還是指針接收器都不相關。IFIG
package main
import "fmt"
type IF interface {
G() IG
}
type F struct {
g IG
}
func (f *F)G() IG {
return f.g
}
type IG interface {
G()
}
type G struct{
i int
}
func (g *G)G() {
g.i++
fmt.Println("Gee, ", g.i)
}
func main() {
f := F{&G{1}}
f.G().G()
}
需要指向接口的指針是非常罕見的,因此請確保您認為“接口由指針滿足”而不是“指向接口的指針”。
- 1 回答
- 0 關注
- 106 瀏覽
添加回答
舉報