タイトル: 可変長引数
SEOタイトル: 可変長引数 完全ガイド(PHP ...$args / Java varargs / Python *args **kwargs / JS rest 演算子)
| この記事の要点 |
|
可変長引数とは
可変長引数 (Variadic Arguments / Varargs) は、関数を呼び出すときに引数の個数を固定せず任意の数だけ渡せるようにする機能です。受け取る側では多くの言語で配列 (またはリスト・タプル) として扱います。
「最低 1 個、最大何個でも受け取りたい」「呼び出し側でその都度個数が変わる」といったときに重宝します。コレクションを引数で 1 つ渡すか、可変長引数で書き並べるかは、API 設計の好みの問題です。
主要言語の記法
| 言語 | 記法 | 受け取り型 |
|---|---|---|
| PHP | function f(...$args) | 配列 |
| JavaScript | function f(...args) | 配列 |
| Java | void f(String... args) | 配列 |
| Python | def f(*args, **kwargs) | タプル / 辞書 |
| C# | void F(params int[] args) | 配列 |
| Kotlin | fun f(vararg args: String) | 配列 |
| Go | func f(args ...int) | スライス |
| Rust | マクロでのみサポート (println! 等) | - |
PHP
function testFunc(int ...$args): int {
return array_sum($args);
}
echo testFunc(1, 2, 3); // 6
echo testFunc(); // 0 (空配列)
echo testFunc(...[10, 20, 30]); // 60 (配列を展開して渡す)
// 通常引数 + 可変長 (可変長は末尾)
function greet(string $prefix, string ...$names): void {
foreach ($names as $n) echo "$prefix $n\n";
}
greet("Hello", "Alice", "Bob");
JavaScript
// ES6 の Rest パラメータ
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(...[10, 20, 30])); // 60 (Spread で展開)
// 残余引数は末尾のみ
function logAll(prefix, ...lines) {
lines.forEach(l => console.log(prefix, l));
}
Java
public static int sum(int... nums) {
int total = 0;
for (int n : nums) total += n;
return total;
}
sum(1, 2, 3); // 6
sum(); // 0
sum(new int[]{10, 20, 30}); // 60 (配列も渡せる)
// printf も Object... を取る典型的な varargs API
System.out.printf("%s is %d%n", "age", 30);
Python (*args / **kwargs)
def f(*args, **kwargs):
print(args) # タプル
print(kwargs) # 辞書
f(1, 2, 3, name="Alice", age=30)
# (1, 2, 3)
# {'name': 'Alice', 'age': 30}
# 呼び出し側で展開
nums = [1, 2, 3]
opts = {"name": "Bob"}
f(*nums, **opts)
| 記号 | 意味 |
|---|---|
*args | 位置引数をタプルとして受け取る |
**kwargs | キーワード引数を辞書として受け取る |
* | 呼び出し時にイテラブルを展開 |
** | 呼び出し時に辞書を展開 |
ルールと注意
- 可変長引数は引数リストの末尾にしか書けない (どの言語も共通)
- 1 つの関数に可変長引数は原則 1 つ (Python の
*args+**kwargsはセット扱い) - 呼び出し側では0 個でも渡せる (型は空配列 / 空タプル)
- 配列を渡したいときはスプレッド構文 (
...arr/*arr) を使う - パフォーマンス的にはほぼ通常の関数呼び出しと同じ。可読性で選んで OK
TypeScript
function sum(...nums: number[]): number {
return nums.reduce((a, b) => a + b, 0);
}
// タプル型で個数 / 型を厳密に
function point(...args: [number, number]): string {
const [x, y] = args;
return `(${x}, ${y})`;
}
// 先頭固定 + 可変長
function log(level: string, ...messages: string[]) {
messages.forEach(m => console.log(`[${level}]`, m));
}
C#
public static int Sum(params int[] nums) {
int total = 0;
foreach (var n in nums) total += n;
return total;
}
Sum(1, 2, 3); // 6
Sum(new[] { 10, 20 }); // 配列を直接渡せる
Sum(); // 0 (空配列)
Go
func Sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
Sum(1, 2, 3)
nums := []int{10, 20, 30}
Sum(nums...) // スライスを展開して渡す
典型的な実用パターン
| パターン | 例 |
|---|---|
| ログ出力 | printf(fmt, ...args) |
| Math.min / max | Math.min(...arr) で配列の最小値 |
| 関数の引数転送 | function wrap(...args) { return inner(...args); } |
| SQL の IN 句構築 | 任意個の値を受け取って IN (?, ?, ?) |
| テストヘルパ | assertEquals(expected, ...actuals) |
FAQ
Q: 配列を引数で渡すのと可変長引数、どちらが良い?
A: 呼び出し側が静的に個数を書けるなら varargs、すでに配列で持っているなら配列引数。両対応するには varargs + スプレッドが便利。
Q: 型チェックは効く?
A: PHP 8 / Java / TypeScript などでは各要素の型を指定でき、不正な型はコンパイル時に弾けます。
Q: メソッドオーバーロードと衝突したら?
A: Java では固定長のシグネチャが優先されます。曖昧にしたくないなら明示キャストで呼び出します。
Q: パフォーマンスへの影響は?
A: 多くの言語で毎回配列が新規生成されるため、ホットループでミリ秒級にこだわる場面では避けるか配列を直接受け取るシグネチャを用意します。通常のアプリ用途では誤差です。
Q: ジェネリクスとの組み合わせ
A: TypeScript の や Java の のように、可変長 + ジェネリクスは便利な組み合わせです。
関連
- スプレッド構文 / Rest パラメータ — 配列の展開記法
- 関数の引数 — デフォルト引数 / 名前付き引数