LoginSignup
17
11

More than 5 years have passed since last update.

Golang 関数引数のスライスはポインタで渡すべき?

Posted at
func insertList(rows []RowColumn) error {
    ...
}

みたいなコードを書いたらコードレビューにて, 配列は値渡しにするとコピーが大きいからポインタ渡しの方がいいのでは?という指摘をされたので調査.
(※弊社は基本Pythonの会社でございます)

Golang では関数の引数は基本的に値渡しである

これは公式言語仕様にもそうあります.
http://golang-jp.org/ref/spec#Calls

In a function call, the function value and arguments are evaluated in the
usual order. After they are evaluated, the parameters of the call are
passed by value to the function
and the called function begins execution.
The return parameters of the function are passed by value back to the
calling function when the function returns.

つまり要素50のスライスを関数に引数として渡すとコピーを生成する?

スライスと配列は同じもの?

配列(array)は特定の型の0個以上の固定長列です.

var l [3]int = [3]int{1, 2, 3}

配列を関数の引数に渡すと配列のコピーが生成されるので要素数によっては非効率とのことです. (書籍 プログラミング言語Go より)
C言語等では配列を関数の引数に渡すと先頭要素のポインタを渡しとなるのでこの点は注意です.

次にスライス(slice)は要素が全て同じ型であることは配列と同様ですが, こちらは可変長です.
再び 「プログラミング言語Go」 より, 「スライスとは配列の要素の部分列へアクセスする軽量なデータ構造であり, そのような配列をスライスの基底配列と呼ぶ. スライスはポインタ、長さ、容量の三つの構成要素を持つ」とあります.
さらにポインタはスライスを通して到達可能な配列の最初の要素を指すらしいです.(必ずしも配列の最初の要素とは限らない)
長さはスライスの要素数, 容量はスライスの開始から基底配列の終わりまでの要素数です.

つまり関数引数としてのスライスは?

スライス自体が配列へのポインタを持っているため, さらにスライスのポインタを引数にするというのはよろしくないです.
またまた 「プログラミング言語Go 」より, 「スライスのコピーは基底配列に対するエイリアスを作成します」とのことです.
配列の要素コピーは作らないのでスライスはそのまま渡す, でよさそうです.

まあエイリアスってことは関数内部でスライス変更すると元のスライスも変わるんですけどね.(これは良し悪し)

17
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
11