6
7

More than 5 years have passed since last update.

引数を左から右へ受け流す

Posted at

プログラムを書いていると、状況によっては、「もらった引数を使って別な関数・メソッドに処理を丸投げする」必要が出てくる場合があります。ここでは、そのような例を示してみます。

JavaScript…配列のようで配列でないもの

JavaScriptの関数では、宣言した仮引数とは別に、argumentsという、すべての引数を詰め込んだ「配列のようなオブジェクト」1が渡されているので、これを使って別な関数をapplyすることで、すべての引数をそのまま渡せます(applyの引数は「配列のようなオブジェクト」で大丈夫です)。

なお、applyの第1引数は呼び出し先でthisになるオブジェクトです。ただの関数なら気にしなくて構いませんが、メソッドを呼ぶ際はきちんと設定しましょう。

apply.js

//foo()からbar()をそのまま呼ぶ

function foo(hoge, piyo){
  bar.apply(this, arguments);
}

Ruby…必殺、splat

Rubyの場合、メソッドの唯一の引数を*argsのように*を前置して宣言しておくと、それがすべての引数の入った配列になります。逆に、引数を渡す段階で*を前置させると、その配列の中身を引数に並べてくれます。

splat.rb
def foo(*args)
  bar(*args)
end

構文解析上の問題について

上の例ではbar(*args)とかっこが付いています。かっこを外した場合、bar*argsという3つの要素が並ぶことになりますが、それはbarargsの掛け算、と取れなくもない状況です。ここでは、bar *argsのように、*前だけ空白を入れた場合は、メソッド呼び出しをsplatしているものと解釈され、それ以外のbar*argsbar * argsは掛け算として解釈されます2。1つ目の引数をsplatする場合には、かっこを付けたほうがいいかもしれません(かっこありならbar(* args)でも問題ありません)。

ブロックは…?

まとめて*argsで受け取っても、ブロックは取得できません。&blockとしてブロックを引数として受け取って、別なメソッドを呼ぶ際にも&blockとしてブロックを渡す形にしましょう。

block.rb
def foo(*args, &block)
  bar(*args, &block)
end

なお、&blockとしたメソッドにブロックが渡されなかった場合、この変数はnilとなりますが、&nilとすると「ブロックを渡さない」という意味になるので、block_given?によって条件分岐する必要もなく、ブロックがあってもなくてもそのまま対応可能です。


  1. 数値プロパティとlengthを持つオブジェクト。JavaScriptではよく使われる術語です。 

  2. +-などでも、a +ba(+b)のようなメソッド呼び出しと解釈されるので注意が必要です。 

6
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7