いろんな言語で可変長引数
関数の引数を任意の個数だけ渡せる機能は、多くの言語にありますが、それぞれ微妙に仕様が違っています。
C言語
C言語では、学習で最初に使うようなprintf
も可変長の引数で構成されていますが、そういう関数を作ろうとすれば意外とやりづらいものです。
stdargs.h
というファイルに、可変長引数用のマクロが用意されています。
-
va_start
…引数ポインタの初期化 -
va_arg
…引数の取得 -
va_end
…引数ポインタの後始末
実装の特徴として、以下のことがあります。
-
va_start
に、可変引数になる直前の引数を渡さないといけないので、引数0個で呼び出すことは不可能です。 - 可変長引数の終わりをシステム側で知ることは不可能なので、「
printf
のように、固定の引数でどんな引数が続くか伝える」「(ポインタ引数が続くのであれば最後にNULL
を入れるというように)引数の終わりを示す値を決めておく」などが必要になります。 - (printfでは例外的にチェックしてくれることもありますが)コンパイラによる型チェックはありません。実際に渡した引数と違う型で取得しようとした場合、どんな動作をするかはわかりません。
- 配列を展開して引数にするような、正当な方法もありません。
JavaScript
ES5まで
ES5までのJavaScriptの場合、可変長引数と銘打った特別な記法はありませんが、「仮引数と実引数で数が一致しなくても問題ない」ということもあって、可変長引数自体には対応できます。
JavaScriptの関数では、引数がarguments
という「配列のようなオブジェクト」に入っていて、arguments.length
で引数の個数を取得できます。なお、仮引数があった場合に、仮引数と同じ位置のarguments
の要素が連動する、という挙動がありましたが、ES5のstrictモードでは廃止されています。
そのまま添字をfor
で回しても構いませんし、本当の配列に変換したければ、Array.prototype.slice.call(arguments)
で可能です。
なお、配列の中身を引数リストに変換したい場合は、関数.apply(thisにするオブジェクト,配列)
とすれば可能です。
ES6
ES6では、PHPと同じような...
(spread operator)で、「可変長の引数を配列で受け取る」「引数に配列などを展開して渡す」ことが可能となっています。なお、ES6のArrow Function(=>
を使った関数表記)では、arguments
も外側にあるものを引き継ぐので要注意です(MDN)。素直にspread operatorで書きましょう。
Ruby
Rubyは可変長引数を明示的にサポートしていますし、引数の数も厳密に取ります。仮引数の宣言の際に、*
を前置させた引数があると、それが残りの引数を配列として受け取ります(性質上、引数リストに1つしか書けません)。
def foo (arg1, *rest)
# 1個以上の引数が必要
end
def bar (*args)
# いくつでも問題なし
end
def baz (*args, last)
#別に*付き引数は最後でなくてもいい
end
配列を展開して引数にしたい場合も、method(*arr)
のように書くことで展開ができます。
PHP
PHPの場合、PHP 5.6以降では...
という構文ができていて、Rubyでの*
のように、可変長引数を自動で配列に詰めてくれます。そして、この引数リストにタイプヒントを付けることも可能です。
PHP 5.5以前の場合も、関数は仮引数以上の個数の引数を受け取ることができて、func_get_args
やfunc_num_args
などの関数で処理することができます。
引数として配列を展開したい場合、PHP 5.6以降では...
を使うことができますし、それ以前でもcall_user_func_array
を使えばできなくはないです。
Author And Source
この問題について(いろんな言語で可変長引数), 我々は、より多くの情報をここで見つけました https://qiita.com/jkr_2255/items/3f15e12bb2cc331ee904著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .