5

次のようなオプションの引数の長いリストを持つメソッドがあります。

def foo(foo = nil, bar = nil, baz = nil, qux = nil)
    # no-op
end

メソッドを呼び出して分割ハッシュをパラメーターとして渡すと、キーをメソッドパラメーターと照合することで、ハッシュ項目がパラメーターにマップされると思いました。

params = { bar: 'bar', foo: 'foo' }
foo(*params)

残念ながら、分割ハッシュを使用してメソッドを呼び出した後でローカル変数を調べると、分割配列を渡した場合に期待するものが正確に得られますが、それは私が望んでいたものではありません。

foo == [:bar, 'bar'] # hoped: foo == 'foo'
bar == [:foo, 'foo'] # hoped: bar == 'bar'

私はここで何が欠けていますか?

4

2 に答える 2

8

(この回答は、質問が行われたときに最新であったRubyのバージョンを参照しています。今日の状況については編集を参照してください。)

Rubyは、名前による引数の受け渡しをサポートしていません。スプラット演算子( )は、それを*呼び出すことによって任意の列挙可能オブジェクトを展開しto_ary、結果を引数リストにスプライスします。あなたの場合、渡す列挙可能なものはハッシュであり、キーと値のペアの配列に変換されます。

[2] pry(main)> params.to_a
=> [[:bar, "bar"], [:foo, "foo"]]

したがって、関数の最初の2つの引数は、値[:bar, "bar"][:foo, "foo"](パラメーター名に関係なく)になります。

Rubyのキーワード引数に似たものが必要な場合は、最後の引数として関数にハッシュを渡すときに中括弧が不要であるという事実を利用できます。

def foo(opts = {})
    bar = opts[:bar] || <default>
    foo = opts[:foo] || <default>
    # or with a lot of parameters:
    opts = { :bar => <default>, :foo => <default>, ... }.merge(opts)
end

foo(foo: 3)  # equivalent to foo({ foo: 3 })

編集

バージョン2.0以降、Rubyは専用構文の名前付き引数をサポートするようになりました。それを指摘してくれたユーザーjgoyonに感謝します。

于 2012-08-26T10:58:07.607 に答える
2

この問題は、名前付きパラメーターとしてよく知られています。Rubyには名前付きパラメーターがないため、これを処理する従来の方法は次のとおりです。

def foo(options = {})
  options = {:foo => nil, :bar => nil, :baz => nil, qux => nil}.merge(options)
  ..
end

またはActiveSupport::CoreExtensions::Hash::ReverseMergeから使用Rails

def foo(options = {})
  options.reverse_merge!{:foo => nil, :bar => nil, :baz => nil, qux => nil}
  ..
end

将来のバージョンでは、Ruby2.0で名前付きパラメーターを使用できるようになります

def foo(foo: nil, bar: nil, baz: nil, qux: nil)
  puts "foo is #{foo}, bar is #{bar}, baz is #{baz}, ..."
  ..
end
于 2012-08-26T11:15:10.267 に答える