KDOC 253: GoでN段階に可変長引数を渡す
この文書のステータス
- 作成
- 2024-10-10 貴島
- レビュー
- 2024-10-28 貴島
概要
Goの可変長引数は、関数定義側では左側に ...
をつけて示す(...args
)。関数内ではスライスとして使える。
また、関数呼び出し側ではスライスの右側に ...
をつけてスライスの要素を可変長引数として渡せる(slice...
)。
package main import "fmt" // func Print(a ...any) (n int, err error) {} func main() { fmt.Print("a", "b", "c") fmt.Println() // 改行 fmt.Print([]any{"a", "b", "c"}...) }
abc abc
多くのユースケースをサポートする、オプショナルな項目の多いタイプのプログラムでは、この構文を多用するものがある1。特定のオプショナルな項目の組み合わせを関数化して、さらにその関数にオプショナルな項目をつける、というようなことだ。そういう場合は直感的でなく、少し目を慣らさないといけない。コードで見てみる。
package main import "fmt" func main() { run1("a", "b", "c") fmt.Println() // 改行 run2("c") } func run1(opts ...string) { for _, str := range opts { fmt.Print(str) } } func run2(opts ...string) { run1(append([]string{"a", "b"}, opts...)...) }
abc abc
run1()
では “a”, “b”, “c” がオプショナルだが、 run2()
では “c” だけがオプショナルになっている。 run2()
では “b”, “c” は自動で渡される。利用者は長大なオプショナル引数を渡すことなく、プリセットの機能をすぐ利用できる。いっぽうで、細かく引数を指定して自分のケースに合わせたい利用者の要望も満たせている。
1つずつ見る。
opts
-> スライス...opts
-> スライスを展開してappendの可変長引数となるappend
のシグネチャfunc append(slice []Type, elems ...Type) []Type
append([]string{"a", "b"}, opts...)
-> これは合体したスライスとなる- つまり
[]string{"a", "b", "c"}
となる
- つまり
append([]string{"a", "b"}, opts...)...
-> スライスを展開してrun1の可変長引数となる- つまり
run1("a", "b", "c")
というように呼び出す
- つまり
関連
- KDOC 59: ECSを使ってサンプルゲームを作る。コードを読む中でよく見かけたため、書いておくことにした