Go の可変長引数(variadic functions)
Go では、関数の引数の数を固定せず、任意の個数の引数を受け取れる「可変長引数」がサポートされている。fmt.Println のように、いくつでも値を渡せる関数は、この仕組みで実現されたものだ。
可変長引数の基本構文
引数の型の前に ... を付けると、その引数は可変長になる。関数の内部では、可変長引数はスライスとして扱われる。
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(10, 20)) // 30
fmt.Println(sum()) // 0(引数なしも可)
}引数をまったく渡さない場合、関数内のスライスは長さ 0 の空スライスになる。nil ではないため、range でループしてもパニックにはならない。
可変長引数の位置の制約
可変長引数は、関数の最後のパラメータにのみ指定できる。通常の引数と組み合わせることは可能だが、可変長引数を先頭や中間に置くことはできない。
// OK: 通常引数の後に可変長引数
func greet(prefix string, names ...string) {
for _, name := range names {
fmt.Printf("%s, %s!\n", prefix, name)
}
}
func main() {
greet("Hello", "Alice", "Bob", "Charlie")
}この制約があることで、コンパイラはどこまでが通常の引数で、どこからが可変長引数かを明確に区別できるようになっている。
スライスを可変長引数に展開する
既存のスライスを可変長引数の関数に渡したいときは、スライスの後ろに ... を付ける。これにより、スライスの各要素が個別の引数として展開される。
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
numbers := []int{5, 10, 15}
result := sum(numbers...) // スライスを展開して渡す
fmt.Println(result) // 30
}numbers... のように書くと、sum(5, 10, 15) と呼び出したのと同等になる。ただし、展開と個別の値を混在させることはできない点に注意が必要だ。
sum(1, 2, 3) のように値を直接並べる。引数の数が少ないときに便利
sum(nums…) のようにスライスごと渡す。動的に数が決まる場合に使う
標準ライブラリでの活用例
Go の標準ライブラリには、可変長引数を活用した関数が数多く存在する。
// fmt.Println: 任意の数の値を出力
fmt.Println("a", "b", "c")
// fmt.Sprintf: フォーマット文字列と可変長引数
msg := fmt.Sprintf("%s is %d years old", "Alice", 30)
// append: スライスに要素を追加
s := []int{1, 2}
s = append(s, 3, 4, 5)
// append でスライス同士を結合
a := []int{1, 2}
b := []int{3, 4}
a = append(a, b...)append はビルトイン関数だが、可変長引数の仕組みと同じインターフェースを持っている。第 2 引数以降に複数の値を渡すことも、スライスを ... で展開して渡すことも可能だ。
any 型との組み合わせ
型の異なる引数を受け取りたい場合は、any(interface{} のエイリアス)と組み合わせる。fmt.Println が任意の型を受け取れるのも、この方法による。
func debugLog(values ...any) {
for i, v := range values {
fmt.Printf("[%d] %T: %v\n", i, v, v)
}
}
func main() {
debugLog("hello", 42, true, 3.14)
// [0] string: hello
// [1] int: 42
// [2] bool: true
// [3] float64: 3.14
}any を使うと柔軟性は高まるが、型安全性は失われる。実行時に型アサーションや型スイッチで型を判定する必要があるため、必要な場面に絞って使うのが望ましい。可変長引数は Go のシンプルな構文のなかで柔軟性を確保する重要な仕組みであり、標準ライブラリの設計思想にも深く組み込まれている。