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を使ってRPGを作る。コードを読む中でよく見かけたため、書いておくことにした