2012-08-26 43 views
4

我有一個可選的參數,如冗長的列表的方法:如何將散列項映射到方法參數?

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' 

我在這裏缺乏什麼?

回答

8

(這個答案指的是紅寶石的版本是當前當有人問。請參閱今天的情況,編輯。)

紅寶石不支持通過名字傳遞參數。splat operator*)通過調用to_ary來展開任意枚舉並將結果拼接到參數列表中。在你的情況,你通過在枚舉是一個哈希,它被改造成鍵 - 值對的數組:

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

因此函數的前兩個參數將是值[: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現在支持named arguments並提供了一種專用的語法。感謝用戶jgoyon指出。

2

這個問題衆所周知的命名參數。因爲Ruby沒有命名的參數所以這裏的傳統方式來對付它:

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

或使用ActiveSupport::CoreExtensions::Hash::ReverseMergeRails

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

在將來的版本的Ruby 2.0將可以使用命名參數

def foo(foo: nil, bar: nil, baz: nil, qux: nil) 
    puts "foo is #{foo}, bar is #{bar}, baz is #{baz}, ..." 
    .. 
end