LoginSignup
1
0

More than 3 years have passed since last update.

【Go】値レシーバとポインタレシーバの違いについて

Last updated at Posted at 2020-08-22

※注意: この記事ははあくまで個人学習用に整理しただけの記事で、内容としては不完全なものになります。読んでも参考にならない可能性が高いです。

構造体のメソッドを作成するにあたり、値レシーバとポインタレシーバの二つの方法があった。
この二つの違いがわかっていなかった為、まとめてみる。

A Tour of 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()) // 50
}

50 と表示される。
上記の Scale メソッドがポインタレシーバになっている。

この Scale のレシーバの * を消して、値レシーバとして実行してみる。

値レシーバ

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()) // 5
}

v.Scale(10) で10倍にしているはずが、反映されず 5 になってしまった。

A Tour of Go の解説では以下のように書いてある。

変数レシーバでは、 Scale メソッドの操作は元の Vertex 変数のコピーを操作します。 (これは関数の引数としての振るまいと同じです)。 つまり main 関数で宣言した Vertex 変数を変更するためには、Scale メソッドはポインタレシーバにする必要があるのです。

なるほど。

変数を変更したい場合にポインタレシーバを使うんですね。
そして上記の例の Abs メソッドのように変数の変更をしない場合は値レシーバを使用し、戻り値で処理結果を戻し、呼び出し元でその値を使用すると。

なるほどです。一旦ざっくり理解した。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0