yyh-gl's icon

yyh-gl's Tech Blog

技術ネタ中心のブログです。主な扱いはバックエンド技術と設計です。

yyh-gl

1 分で読めます

featured

Goにおける参照渡し=ポインタの値渡し

Goでは関数にパラメータを渡すとき、全て値渡しで実現されています。
(C派生の言語はすべてそうらしいです)

じゃあ、参照渡しって何?ってなりますよね。

参照渡し=ポインタの値渡しです。
つまり、ポインタそのものを渡しているわけではなく、ポインタのコピーを渡しています。


値渡しと参照渡しの差は、内部の値をコピーするかどうかです。
こちらについては後ほど例を交えて説明します。


今回の内容はGo公式ドキュメントの『Pointers and Allocation』 の章に
詳細な記載があります。

本記事では、『Pointers and Allocation』 から要点を抜粋して紹介します。

値渡しと参照渡しの違いは内部値のコピー有無

まずは、先述した

値渡しと参照渡しの差は、内部の値をコピーするかどうかです。

について詳しく見ていきます。

公式ドキュメント『When are function parameters passed by value?』 の節に以下の記述があります。

For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to.

たとえば、int値を関数に渡すとintのコピーが作成され、ポインター値を渡すとポインターのコピーが作成されますが、ポインターが指すデータは作成されません。

つまり、

  • 値渡し:値のコピーが作成される
  • 参照渡し:ポインタのコピーは作成されるが、ポインタが指すデータ(値)のコピーは作成しない

といった差があります。

図にすると以下のとおりです。
同じ色の箱はアドレスが同じだと考えてください。
(図が下手なところはほっといてあげてください🙇‍♂️)

大きな差がありますね。

この差により、例えば、多くのフィールドを持つ構造体を関数の引数やレシーバとして渡す場合、
値渡しでは全フィールドのコピーが行われてしまうため
パフォーマンス的に良くないといった違いが生まれてきます。


無駄なコピーを行わないために全て参照渡しにしとけばいいか、
というとそれはまた別で考慮すべき点が出てきます。

「値渡し または 参照渡しのどちらを使用するか」については多くの議論がなされています。

コードで確認

では、最後にここまでの内容をコードで確認して終わります。

playground

上記のplaygroundを実行すると、以下のように出力されました。
(アドレス部分は実行ごとに異なります)

main()における構造体のアドレス:            0xc00010a040
main()におけるnameのアドレス:             0xc00010a040
PassByReference()における構造体のアドレス: 0xc000102020
PassByReference()におけるnameのアドレス:  0xc00010a040
PassByValue()における構造体のアドレス:     0xc00010a050
PassByValue()におけるnameのアドレス:      0xc00010a050

PassByReference()がレシーバを参照渡しで受け取る関数で
PassByValue()がレシーバを値渡しで受け取る関数です。

main()PassByReference()を比較すると、両者の構造体のアドレスが異なっています。
Human構造体がもつnameフィールドについては同じアドレスを指しています。
つまり、レシーバのポインタはコピーしたものを参照していますが、
フィールドの値はコピーではなく、main()で定義したものが使用されています。
先述の内容と一致しますね。

一方で、main()PassByValue()を比較すると、
両者の構造体のアドレスおよびフィールドのアドレスがすべて異なります。
すなわち、レシーバのポインタおよびフィールドのすべての値に関して、コピーしたものを参照しています。

こちらも先述の内容と一致します。

納得!


ちなみに、なぜすべて値渡しで実現しているかについては、
先程紹介した下記の記事で触れられています。

Yury Pitsishin『Pass by pointer vs pass by value in Go』
→「Passing by value often is cheaper」の章

最近の投稿

About

東京で働くソフトウェアエンジニアです。バックエンドがメインですが、フロントエンドやインフラもさわっています。