«前の日記(2010年06月17日) 最新 次の日記(2010年06月24日)» 編集

Matzにっき


2010年06月18日 [長年日記]

_ [Ruby] Ruby2.0の新機能(かもしれないもの)(4) keyword arguments

注意。このエントリはRuby 2.0に入るかもしれない機能について述べていますが、本機能が本当に2.0に採用されるかどうかは、未定です。

「まだあるのか」とか思われそうだけど、まだあるんです。

今度は長年採用すると言いつつ、ほったらかしの最右翼、キーワード引数である。 調べたら、キーワード引数については、2003年のRubyConfではすでに話題にしている。 どんだけ前から口にしてたんだ。「やるやる詐欺」だな(苦笑)。

その時の仕様はこんな感じ。

def foo(a, b: 42, **keys)
   p [a,b,keys]
end
foo(1)             # => [1,42,{}]
foo(2, b: 5)       # => [2,5,{}]
foo(3, b: 4, c: 6) # => [3,4,{:c=>6}]

まあ、そんなに悪くない。基本的にはこの線を踏襲しようと思う。 文法としては、ブロック引数の直前に

keyword: value,..., **keys

というキーワード引数を置くことができる、というもの。 Pythonと違ってキーワード引数は明示的に指定しなければならない。 通常の引数名が勝手にキーワードになったりはしない。

問題はrest引数と組み合わさった時。

def baz(*rest, a:4, b:0, **keys)
  ...
end

として、以下の呼び出しを行ったらどうなるか。

baz()           # rest=[],a=4,b=0,keys={}
baz(1)          # rest=[1],a=4,b=0,keys={}
baz(a:1)        # rest=[],a=1,b=0,keys={}
baz(a:1,b:2)    # rest=[],a=1,b=2,keys={}
baz(1,2,b:2)    # rest=[1,2],a=4,b=2,keys={}
baz(c:2)        # rest=[],a=4,b=0,keys={c:2}

つまり、以下のルールに従う。

  • 引数が0の場合、キーワード指定は{}とみなす。
  • 引数が1個以上の時、末尾の引数がHashでなければ、キーワード指定は{}とみなす。
  • 引数が1個以上で、末尾がHashであればそれがキーワード指定。引数リストから取り除く※
    • キーワード指定に、キーワード引数があればそれを取り除き、キーワードと同じ名前の変数に代入
    • キーワード指定にキーワードが含まれていなければ、デフォルト値を代入
    • 「**keys」が指定されていない時に、キーワード指定がキーワード引数として定義されていないキーを含む時には、ArgumentError例外

なお、※の部分はRubyConf 2005のキーノートで紹介したものと動作が違う。

この仕様ではキーワード指定はあくまでも通常引数の一部なので、 通常引数の引渡の時には *rest で受けて、 foo(*rest) と呼び出せばよい(はず)。

呼び出し側のキーワード引数は結局は引数リスト末尾のハッシュに過ぎないので、 呼び出し側では foo(**keys) のような文法は(本来は)不要。 ただし、対称性と型チェックのために採用する可能性は、なきにしもあらず(あんまり積極的ではない)。


«前の日記(2010年06月17日) 最新 次の日記(2010年06月24日)» 編集