🏃

【Go】ポインタについて語るときに僕の語ること

2023/11/20に公開

はじめに

  • ポインタとは、メモリアドレスを指し示す特殊な変数のことです。
  • 多くの場合、この概念は初学者にとって抽象的で理解が難しいものです。
  • この記事では、ポインタを使わないと困る具体的なケースとその解決法を通じて、ポインタの理解を深めていきます

なぜ彼は歳を取らないのか(ポインタを使用しない場合の例)

  • まず、人間を定義します

type Person struct {
    Name string
    Age  int
}

  • 人間に名前と年齢を与えて、誕生日を迎えさせます
// ポインタを使用しないバージョン
func birthday(p Person) {
    p.Age++ // この変更は呼び出し元に反映されない
}

func main() {
    person := Person{Name: "Tsukuru", Age: 12}
    birthday(person)
    fmt.Println(person.Age) // 12のまま変わらない
}

  • 一見、彼は歳を取りそうな気がしますが年齢は12歳のままです
  • これは、Go言語では、関数に値を渡す際にデフォルトでは 値渡し(value semantics) [1] が使われることが起因しています
  • 要はbirthday関数は「とりあえず、年齢を加算するだけ」の関数であり。「誰の年齢を加算するか」は意識していません(参照がないため)。

モヤモヤした人のイラスト(女性)

  • ここで参照を明示してあげよう!となりますよね
  • いよいよポインタの出番です

無事、13歳に(ポインタを使用する場合の例)


// Personを*Personに
func birthday(p *Person) {
    p.Age++ // この変更は呼び出し元に反映される
}

func main() {
    person := Person{Name: "Alice", Age: 30}
    birthday(&person) // personを&personに
    fmt.Println(person.Age) // 13に増加
}

ポイント

  1. personは関数に変数のアドレスを渡すために & を使用します
  2. デリファレンス(ポインタ変数から値を参照)するために * を使用します

解説

  • 1について

    • & を付与することで、personの参照が明示されます
    • これで、受け取り側のbirthday関数は「誰の」を渡せます
  • 2について

    • *を使用することで、ポインタ変数から値を参照できるようになりました
  • つまり、関数に渡す側も受け取る側も参照を認識できるようになりました

  • 晴れて、これで13歳になれるのです

誕生日ケーキに顔を突っ込まれる人のイラスト

最後に

  • 個人的には、難解な概念を理解したいときは「それがなかったら困ること」を考えると理解できることが多いです
  • 今回の例が参考になれば幸いです
  • また、当方はGoの初学者なので間違い等あれば(とても優しく)ご指摘お願いします

引用元

  • タイトル(バイブルです)

https://www.amazon.co.jp/走ることについて語るときに僕の語ること-文春文庫-村上-春樹/dp/4167502100

  • 参考記事

https://zenn.dev/ak/articles/1fb628d82ed79b

https://go.dev/doc/faq#Pointers

special thanksはChatGPT(4.0)

脚注
  1. ... C ファミリーのすべての言語と同様に、Go ではすべてが値によって渡されます。つまり、関数は、パラメータに値を割り当てる代入ステートメントがあるかのように、常に渡されるもののコピーを取得します。 ↩︎

Discussion