go 沒有類。不過你可以為結構體型別定義方法。
方法就是一類帶特殊的 接收者 引數的函式。
方法接收者在它自己的引數列表內,位於 func 關鍵字和方法名之間。
在此例中,abs 方法擁有乙個名為 v,型別為 vertex 的接收者。
package main
import
("fmt"
"math"
)type vertex struct
func
(v vertex)
abs(
)float64
func
main()
fmt.
println
(v.abs()
)}
5
記住:方法只是個帶接收者引數的函式。
現在這個 abs 的寫法就是個正常的函式,功能並沒有什麼變化。
package main
import
("fmt"
"math"
)type vertex struct
func
abs(v vertex)
float64
func
main()
fmt.
println
(abs
(v))
}
你也可以為非結構體型別宣告方法。
在此例中,我們看到了乙個帶 abs 方法的數值型別 myfloat。
你只能為在同一包內定義的型別的接收者宣告方法,而不能為其它包內定義的型別(包括 int 之類的內建型別)的接收者宣告方法。
注:就是接收者的型別定義和方法宣告必須在同一包內;不能為內建型別宣告方法。
package main
import
("fmt"
"math"
)type myfloat float64
func
(f myfloat)
abs(
)float64
return
float64
(f)}
func
main()
1.4142135623730951
你可以為指標接收者宣告方法。
這意味著對於某型別 t,接收者的型別可以用 *t 的文法。(此外,t 不能是像 *int 這樣的指標。)
例如,這裡為 *vertex 定義了 scale 方法。
指標接收者的方法可以修改接收者指向的值(就像 scale 在這做的)。由於方法經常需要修改它的接收者,指標接收者比值接收者更常用。
若使用值接收者,那麼 scale 方法會對原始 vertex 值的副本進行操作。(對於函式的其它引數也是如此。)scale 方法必須用指標接受者來更改 main 函式中宣告的 vertex 的值。
package main
import
("fmt"
"math"
)type vertex struct
func
(v vertex)
abs(
)float64
func
(v *vertex)
scale
(f float64
)func
main()
v.scale(10
) fmt.
println
(v.abs()
)}
50
現在我們要把 abs 和 scale 方法重寫為函式。
package main
import
("fmt"
"math"
)type vertex struct
func
abs(v vertex)
float64
func
scale
(v *vertex, f float64
)func
main()
scale
(&v,10)
fmt.
println
(abs
(v))
}
比較前兩個程式,你大概會注意到帶指標引數的函式必須接受乙個指標:
var v vertex
scalefunc
(v,5
)// 編譯錯誤!
scalefunc
(&v,5)
// ok
而以指標為接收者的方法被呼叫時,接收者既能為值又能為指標:
var v vertex
v.scale(5
)// ok
p :=
&vp.
scale(10
)// ok
對於語句 v.scale(5),即便 v 是個值而非指標,帶指標接收者的方法也能被直接呼叫。 也就是說,由於 scale 方法有乙個指標接收者,為方便起見,go 會將語句 v.scale(5) 解釋為 (&v).scale(5)。
package main
import
"fmt"
type vertex struct
func
(v *vertex)
scale
(f float64
)func
scalefunc
(v *vertex, f float64
)func
main()
v.scale(2
)scalefunc
(&v,10)
p :=
&vertex
p.scale(3
)scalefunc
(p,8
) fmt.
println
(v, p)
}
&
同樣的事情也發生在相反的方向。
接受乙個值作為引數的函式必須接受乙個指定型別的值:
var v vertex
fmt.
println
(absfunc
(v))
// ok
fmt.
println
(absfunc
(&v)
)// 編譯錯誤!
而以值為接收者的方法被呼叫時,接收者既能為值又能為指標:
var v vertex
fmt.
println
(v.abs()
)// ok
p :=
&vfmt.
println
(p.abs()
)// ok
這種情況下,方法呼叫 p.abs() 會被解釋為 (*p).abs()。
package main
import
("fmt"
"math"
)type vertex struct
func
(v vertex)
abs(
)float64
func
absfunc
(v vertex)
float64
func
main()
fmt.
println
(v.abs()
) fmt.
println
(absfunc
(v))
p :=
&vertex
fmt.
println
(p.abs()
) fmt.
println
(absfunc
(*p)
)}
555
5
使用指標接收者的原因有二:
首先,方法能夠修改其接收者指向的值。
其次,這樣可以避免在每次呼叫方法時複製該值。若值的型別為大型結構體時,這樣做會更加高效。
在本例中,scale 和 abs 接收者的型別為 *vertex,即便 abs 並不需要修改其接收者。
通常來說,所有給定型別的方法都應該有值或指標接收者,但並不應該二者混用。
package main
import
("fmt"
"math"
)type vertex struct
func
(v *vertex)
scale
(f float64
)func
(v *vertex)
abs(
)float64
func
main()
fmt.
printf
("before scaling: %+v, abs: %v\n"
, v, v.
abs())
v.scale(5
) fmt.
printf
("after scaling: %+v, abs: %v\n"
, v, v.
abs())
}
before scaling: &, abs: 5
after scaling: &, abs: 25
指標陣列與陣列指標 go解析
對於指標陣列和陣列指標在c或c 中也經常被討論,尤其對於初學者來說會分辨不清楚。其實在每個詞中間新增乙個 的 就很好理解了,指標的陣列,陣列的指標。本文就通過go語言來分別解釋一下陣列指標與指標陣列。對於指標陣列來說,就是 乙個陣列裡面裝的都是指標,在go語言中陣列預設是值傳遞的,所以如果我們在函式...
go 結構體指標方法與結構體方法的區別
package main import fmt type person struct func v person modifyname name string func main xiaoming.modifyname 小李 fmt.println xiaoming.name 輸出結果如下 c us...
Go方法與併發
go中沒有類,但是可以為結構體定義方法,方法就是一類帶有特殊的接受者引數的函式。方法接受者位於func關鍵字和方法名之間。可以為非結構體型別宣告方法,但不能為其它包內定義的型別的接收者宣告方法,且不能為內建型別宣告方法。函式 package main import fmt func add x in...