プログラムを書いていると、状況によっては、「もらった引数を使って別な関数・メソッドに処理を丸投げする」必要が出てくる場合があります。ここでは、そのような例を示してみます。
JavaScript…配列のようで配列でないもの
JavaScriptの関数では、宣言した仮引数とは別に、argumentsという、すべての引数を詰め込んだ「配列のようなオブジェクト」1が渡されているので、これを使って別な関数をapplyすることで、すべての引数をそのまま渡せます(applyの引数は「配列のようなオブジェクト」で大丈夫です)。
なお、applyの第1引数は呼び出し先でthisになるオブジェクトです。ただの関数なら気にしなくて構いませんが、メソッドを呼ぶ際はきちんと設定しましょう。
//foo()からbar()をそのまま呼ぶ
function foo(hoge, piyo){
bar.apply(this, arguments);
}
Ruby…必殺、splat
Rubyの場合、メソッドの唯一の引数を*argsのように*を前置して宣言しておくと、それがすべての引数の入った配列になります。逆に、引数を渡す段階で*を前置させると、その配列の中身を引数に並べてくれます。
def foo(*args)
bar(*args)
end
構文解析上の問題について
上の例ではbar(*args)とかっこが付いています。かっこを外した場合、bar、*、argsという3つの要素が並ぶことになりますが、それはbarとargsの掛け算、と取れなくもない状況です。ここでは、bar *argsのように、*の前だけ空白を入れた場合は、メソッド呼び出しをsplatしているものと解釈され、それ以外のbar*argsやbar * argsは掛け算として解釈されます2。1つ目の引数をsplatする場合には、かっこを付けたほうがいいかもしれません(かっこありならbar(* args)でも問題ありません)。
ブロックは…?
まとめて*argsで受け取っても、ブロックは取得できません。&blockとしてブロックを引数として受け取って、別なメソッドを呼ぶ際にも&blockとしてブロックを渡す形にしましょう。
def foo(*args, &block)
bar(*args, &block)
end
なお、&blockとしたメソッドにブロックが渡されなかった場合、この変数はnilとなりますが、&nilとすると「ブロックを渡さない」という意味になるので、block_given?によって条件分岐する必要もなく、ブロックがあってもなくてもそのまま対応可能です。