假設我們有一個簡單的介面和實作:
type Vertex struct {
X int
Y int
}
type Abser interface {
Abs() float64
}
func (v Vertex) Abs() float64 {
sum := float64(v.X v.Y)
return math.Sqrt(sum)
}
現在我有一個介面變數:
var abser Abser
我想為它設定一個頂點。我可以設定一的值,或一的地址:
v := Vertex{1, 1}
abser = v
abser = &v
兩者有什么區別?為什么設定頂點地址有效?這如何與介面在引擎蓋下的作業方式聯系起來?我對 Go 還是很陌生,所以任何幫助將不勝感激??
uj5u.com熱心網友回復:
在轉到型別的系統中,一種方法使用的值-接收器型別定義T中尋找定義T和*T,即:
func (v Vertex) Abs() float64 {...}
這對v和 都有效*v。方法本身總是接收v.
定義為的方法*T只定義為*T,而不定義為T。那是:
func (v *Vertex) SetX(newx float64) {v.X=newx}
該方法SetX僅在接收器可尋址時有效。這是必要的,這樣您就不會撰寫丟失資料的代碼。例如:
m:=map[string]Vertex{}
m["a"]=Vertex{}
m["a"].SetX(1) // This fails! m["a"] is not addressable
如果上述情況沒有失敗,那么SetX將設定一個副本m["a"],并且效果將丟失,因為更新的副本沒有放回地圖中。
回到介面:您的Abser介面由任何實作Abs() float64. 基于以上討論,Vertex和 都*Vertex實作Abser.
假設您定義Vertex.Abs為:
func (v *Vertex) Abs() float64 {...}
然后,只*Vertex實作Abser,所以:
abser = v // This would fail
abser = &v // This would work
uj5u.com熱心網友回復:
首先,在 Go 中,一切都是按值傳遞的。
指標按值傳遞 - 使用指標的副本。
切片按值傳遞——復制指向底層陣列的指標、長度的整數值和容量的整數值。
介面也按值傳遞 - 使用介面值的副本。
如果您以這種方式考慮它會有所幫助。
現在,讓我們專注于介面:
一個介面值由兩部分組成:
- 指向介面表的指標
- 指向實際值的指標
所以當你傳遞一個介面時,你實際上是在復制兩個指標。
現在,對于滿足介面的型別,它需要具有介面所需的方法。如果任何方法使用指標接收器(例如func (v *Vertex) Abs() float64 {...}在您的示例中),那么您將需要一個指向該值的指標來滿足介面,這就是您需要獲取它的地址的原因。
假設所有方法都不需要指標接收器(例如func (v Vertex) Abs() float64 {...})。那么您就不需要指定地址,因為您只需傳遞它而不獲取其地址。
我希望這能回答你的問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/314988.html
