[英]Golang pointers
我目前正在學習用Go語言編程。 我在理解Go指針方面遇到了一些困難(現在我的C / C ++還很遠......)。 例如,在Tour of Go#52( http://tour.golang.org/#52 )中,我讀到:
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}
但如果不是
func (v *Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}
我寫:
func (v Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}
甚至:
func (v Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}
反之亦然:
func (v *Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}
我得到了完全相同的結果。 是否存在差異(記憶方面等)?
您的示例使用了兩種不同的Go語言規則:
可以從具有值接收器的方法導出具有指針接收器的方法。 因此func (v Vertex) Abs() float64
將自動生成另一個方法實現:
func (v Vertex) Abs() float64 { return math.Sqrt(vX*v.X+vY*vY) } func (v *Vertex) Abs() float64 { return Vertex.Abs(*v) } // GENERATED METHOD
編譯器將自動找到生成的方法:
v := &Vertex{3, 4} v.Abs() // calls the generated method
Go可以自動獲取變量的地址。 在以下示例中:
func (v *Vertex) Abs() float64 { return math.Sqrt(vX*v.X+vY*vY) } func main() { v := Vertex{3, 4} v.Abs() }
表達式v.Abs()
等效於以下代碼:
vp := &v vp.Abs()
有區別。 例如,非指針接收器形式強制該方法在副本上工作。 這樣,該方法無法改變它所調用的實例 - 它只能訪問該副本。 在時間/內存性能/消耗等方面可能無效。
OTOH,指向具有指針接收器的實例和方法的指針允許在需要時容易地實例共享(和變異)。
更多細節在這里 。
區別在於傳遞參考與傳遞值。
在func f(v Vertex)
,參數被復制到參數v
。 在func f(v *Vertex)
中,傳遞指向現有Vertex
實例的指針。
使用方法時,可以為您完成一些解除引用,因此您可以使用方法func (v *Vertex) f()
並在不先獲取指針的情況下調用它: v := Vertex{...}; vf()
v := Vertex{...}; vf()
。 這只是一種語法糖,AFAIK。
這些例子有兩個主要區別:
func (v *Vertex) Abs()....
接收器將通過引用傳遞給v,你只能在指針上調用此方法:
v := Vertex{1,3}
v.Abs() // This will result in compile time error
&v.Abs() // But this will work
另一方面
func (v Vertex) Abs() ....
您可以在指針和結構上調用此方法。 即使您在指針上調用此方法,接收器也將按值傳遞 。
v := Vertex{1,3}
v.Abs() // This will work, v will be copied.
&v.Abs() // This will also work, v will also be copied.
您可以聲明func (v *Vertex)
和func (v Vertex)
。
正如規范所說
如果方法集x(類型)x包含m並且參數列表可以分配給m的參數列表,則方法調用xm()有效。 如果x是可尋址的並且&x的方法集包含m,則xm()是(&x).m()的簡寫:
在你的情況下,如果方法是可尋址的,v.Abs()是&v.Abs()的簡寫。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.