本日のGo
連続更新は難しい。
ポインタレシーバ
ある宣言した型のメモリにアクセスして値を変更する処理。
package main import ( "fmt" "math" ) type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func (v *Vertex) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f } func main() { v := Vertex{3, 4} v.Scale(10) fmt.Println(v.Abs()) }
Vertex宣言した2つの値に10をかけているのだろう。
最終的に30と40になってAbs関数を実行している。
func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func (v *Vertex) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f } func main() { v := Vertex{3, 4} v.Scale(10) fmt.Println(v.Abs()) }
Vertex型に値を代入してるか、Vertexのポインタ型に値を代入しているかがわかる。
package main import "fmt" type Vertex struct { X, Y float64 } func (v *Vertex) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f } func ScaleFunc(v *Vertex, f float64) { v.X = v.X * f v.Y = v.Y * f } func main() { v := Vertex{3, 4} v.Scale(2) ScaleFunc(&v, 10) p := &Vertex{4, 3} p.Scale(3) ScaleFunc(p, 8) fmt.Println(v, p) }
&VertexでVertexのポインタ型を宣言して初期化している。
p := &Vertex{4, 3}
ScaleFuncの引数は ScaleFunc(v *Vertex, f float64) なのでpを引数に設定する場合はScaleFunc(p, 8)のようにvと違って&をつけない。
ファンクションの宣言のさせ方次第でポインタで与えなくては値を与えるのかそうでないのかが変わるのね。
package main import ( "fmt" "math" ) type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func AbsFunc(v Vertex) float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func main() { v := Vertex{3, 4} fmt.Println(v.Abs()) fmt.Println(AbsFunc(v)) p := &Vertex{4, 3} fmt.Println(p.Abs()) fmt.Println(AbsFunc(*p)) }
この状態だとポインタのことを意識しないで値を出力できる。
func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) }
fmt.Println(v.Abs()) fmt.Println(p.Abs())
この状態だとポインタの中身を意識して出力させてないといけない。
変数vのVertex型のときはvで変数の中身が取り出せるが、変数pのVertexポインタ型のときは*pで変数の中身を取り出す。
func AbsFunc(v Vertex) float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) }
fmt.Println(AbsFunc(v)) fmt.Println(AbsFunc(*p))