🏃
【Go】ポインタについて語るときに僕の語ること
はじめに
- ポインタとは、メモリアドレスを指し示す特殊な変数のことです。
- 多くの場合、この概念は初学者にとって抽象的で理解が難しいものです。
- この記事では、ポインタを使わないと困る具体的なケースとその解決法を通じて、ポインタの理解を深めていきます
なぜ彼は歳を取らないのか(ポインタを使用しない場合の例)
- まず、人間を定義します
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に増加
}
ポイント
- personは関数に変数のアドレスを渡すために & を使用します
- デリファレンス(ポインタ変数から値を参照)するために * を使用します
解説
-
1について
- & を付与することで、personの参照が明示されます
- これで、受け取り側のbirthday関数は「誰の」を渡せます
-
2について
- *を使用することで、ポインタ変数から値を参照できるようになりました
-
つまり、関数に渡す側も受け取る側も参照を認識できるようになりました
-
晴れて、これで13歳になれるのです
最後に
- 個人的には、難解な概念を理解したいときは「それがなかったら困ること」を考えると理解できることが多いです
- 今回の例が参考になれば幸いです
- また、当方はGoの初学者なので間違い等あれば(とても優しく)ご指摘お願いします
引用元
- タイトル(バイブルです)
- 参考記事
special thanksはChatGPT(4.0)
-
... C ファミリーのすべての言語と同様に、Go ではすべてが値によって渡されます。つまり、関数は、パラメータに値を割り当てる代入ステートメントがあるかのように、常に渡されるもののコピーを取得します。 ↩︎
Discussion