我有一个带有冗长可选参数列表的方法,例如:
def foo(foo = nil, bar = nil, baz = nil, qux = nil)
# no-op
end
我认为调用方法并将分割哈希作为参数传递会通过将键与方法参数匹配来将哈希项映射到参数:
params = { bar: 'bar', foo: 'foo' }
foo(*params)
不幸的是,当我在使用拆分哈希调用方法后检查局部变量时,如果我传入一个split数组,我会得到我所期望的,但这不是我希望的:
foo == [:bar, 'bar'] # hoped: foo == 'foo'
bar == [:foo, 'foo'] # hoped: bar == 'bar'
我在这里缺少什么?
答案 0 :(得分:8)
(这个答案是指当问题被提出时最新的Ruby版本。请参阅编辑今天的情况。)
Ruby不支持按名称传递参数。 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指出了这一点。
答案 1 :(得分: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
在未来的版本中,Ruby 2.0可以使用命名参数
def foo(foo: nil, bar: nil, baz: nil, qux: nil)
puts "foo is #{foo}, bar is #{bar}, baz is #{baz}, ..."
..
end