JSゆるふわめも

がっこうでべんきょうしたことをめもがきしてます

ポインタレシーバーと値レシーバー

最近Goは全く触っていないです。 ただ、寝れなくなったのでGoを学習していた時によく分かっていなかったことを少し調べてみました。

それはコイツらです。

type Person struct { Name string }

//値レシーバー
func (p Person) hello() {
  fmt.Printf("Hi, my name is %s", p.Name)
}
//ポインタレシーバー
func (p *Person) hello() {
  fmt.Printf("Hi, my name is %s", p.Name)
}

これらをどう使い分けるのか?よく分かっていませんでした。 ぶっちゃけよく分かっていなくても練習問題は解けたので気にもしてませんでした。

正直今も正しく理解できているか謎ですが、下記のブログを読んで理解したことを意識低くメモします。

skatsuta.github.io

qiita.com

値レシーバーはメソッド定義された型の値をコピーして呼び出されます。 なので、下記のようなNewNameを定義しても呼び出し元の値は変化しません。

type Person struct { Name string }

func (p Person) NewName(newName string) {
 p.Name = newName
}

func main(args string...) {
   p := Person{ Name : taro }
   p.NewName
   fmt.Printf("My name is %s", p.Name) //My name is taro
}

逆にポインタレシーバーの場合は変化します。 つまり、呼び出し元のフィールド値を書き換えたいような場合はポインタレシーバーを使用して、 呼び出し元を変化させたくない(immutable)場合は値レシーバーを使用します。

また、値レシーバーは呼び出し元を丸っとコピーするので大きな構造体に対する呼び出しは高コストになるため避けたほうが良いです。