2012-08-26 42 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