🐕

[Go] ポインタを学ぶ

2021/11/22に公開

エンジニアの皆様、今日も、お疲れ様です。

私は、少し前まで、Ruby on Railsを書いていたため
ポインタという言葉を知りませんでした。
Go言語での実装では、ポインタを使用した変数の受け渡しをよく行います。
初めは理解するのにとても苦しみましたorz

今日はGo言語でのポインタについて復習しつつまとめていきたいと思います。お付き合い下さい。

■ ポインタとは?

メモリ上のアドレス情報を扱えるようになります。

変数に文字列を渡した場合、以下の図のイメージとなります。

var n := "hoge" 

メモリ内にアドレスが割り当てられ
このアドレスに値が保存されます。

変数nのアドレスを取得する場合は、&(アドレス演算子) を使いアクセスすることができます。

fmt.Println(&n) // 12345xxxxx

また、*型名を作るとポインタ型ができます。

var m *string = &n

ポインタ型の変数mを作成し、
変数nのアドレスをm変数に格納しました。

つまり、 n と m は同じアドレスを参照していることになります。

*と&を使いながら、ポインターを扱うことになります。たまに、実装中に扱っている変数がポインターなのかわからなくなる時もあります^^;

■ 実際どのようなところでポインタが使用されるか

関数への値渡しでポインタを使用します。
ポインタを使用しない場合との違いを確認してみましょう。

変数aに10を渡し、その後hogeFuncとpiyoFuncにそれぞれ値を渡します。
hogeFuncとpiyoFuncは引数に対して10を足す処理をしますが、
hogeFuncの引数は、&aを渡し、
piyoFuncはaを渡しています。

func main() {
    a := 10
    fmt.Println(a) // 10
 
    // hogeFuncを呼びaのアドレスを渡す
    hogeFunc(&a)
    fmt.Println(a) // 20
    
    
     // piyoFuncを呼びaの値を渡す
    piyoFunc(a)
    fmt.Println(a) // 10
}

func hogeFunc(a *int) {
    *a += 10
    fmt.Println(*a) // 20
}

func piyoFunc(a int) {
    a += 10
    fmt.Println(a) // 20
}

hogeFuncで処理を行なった方では期待通りに、最初に定義した10に+10された値になりましたが、piyoFuncは10となりました。

同じ処理を行なっているはずですが、hogeFuncとpiyoFuncの値が違います。何故でしょうか?

piyoFuncの引数に値を渡した場合は、
関数が実行される時に値がコピーされ、参照先のアドレスが変わってしまうからです。

func main() {
    a := 10
    fmt.Println(a) // 10
    fmt.Println(a) // &a: 12345xxxxx(aのアドレス)

    // piyoFuncを呼びaの値を渡す
    piyoFunc(a)
    fmt.Println(a) // 10
    fmt.Println(&a) // &a: 12345xxxxx(aのアドレス)
}

func piyoFunc(a int) {
    a += 10
    fmt.Println(a) // 20
    fmt.Println(a) // &a: 6789xxxxx(新aのアドレス)
}

■ まとめ

メモリ上のアドレス情報を扱えるようになります。
&(アドレス演算子)、*を使ってメモリ上のアドレスを取得したり、取得したアドレスに格納されている値を参照できます。

Discussion