如何使用splat和可选的哈希同时在ruby中定义方法?
我能够定义这样的方法:
def test(id, *ary, hash_params) # Do stuff here end
但这使得hash_params
参数成为hash_params
参数。 这些也不起作用:
def t(id, *ary, hash_params=nil) # SyntaxError: unexpected '=', expecting ')' def t(id, *ary, hash_params={}) # SyntaxError: unexpected '=', expecting ')'
有没有办法让它可选?
你不能这样做。 您必须考虑Ruby如何能够确定属于*ary
以及属于可选哈希的内容。 由于Ruby无法读懂你的想法,上面的参数组合(splat + optional)是不可能在逻辑上解决的。
你要么重新安排你的论点:
def test(id, h, *a)
在这种情况下, h
不是可选的。 或者手动编程:
def test(id, *a) h = a.last.is_a?(Hash) ? a.pop : nil # ^^ Or whatever rule you see as appropriate to determine if h # should be assigned a value or not.
通过使用数组扩展extract_options!
在ActiveSupport中支持这一点extract_options!
。
def test(*args) opts = args.extract_options! end
如果最后一个元素是一个哈希,那么它将从数组中弹出并返回它,否则它将返回一个空哈希,这在技术上与你想要的(*args, opts={})
。
ActiveSupport数组#extract_options!
除了caspers回答 :
如果最后一个参数是哈希值,您可以使用splash参数并检查。 然后将哈希作为设置。
一个代码示例:
def test(id, *ary ) if ary.last.is_a?(Hash) hash_params = ary.pop else hash_params = {} end # Do stuff here puts "#{id}:\t#{ary.inspect}\t#{hash_params.inspect}" end test(1, :a, :b ) test(2, :a, :b, :p1 => 1, :p2 => 2 ) test(3, :a, :p1 => 1, :p2 => 2 )
结果是:
1: [:a, :b] {} 2: [:a, :b] {:p1=>1, :p2=>2} 3: [:a] {:p1=>1, :p2=>2}
如果您的array-parameter应该包含最后位置的哈希,这将产生问题。
test(5, :a, {:p1 => 1, :p2 => 2} ) test(6, :a, {:p1 => 1, :p2 => 2}, {} )
结果:
5: [:a] {:p1=>1, :p2=>2} 6: [:a, {:p1=>1, :p2=>2}] {}
您可以(错误地)使用参数列表末尾的可选块:
def test(id,*ary, &block) if block_given? opt_hash = block.call p opt_hash end p id p ary end test(1,2,3){{:a=>1,:b=>2}} # output: # {:a=>1, :b=>2} #Hurray! # 1 # [2, 3]
@Casper是对的。 只有一个参数可以有splat运算符。 参数首先从左到右分配给非splatted参数。 剩余的参数将分配给splat参数。
你可以按照他的建议去做。 你也可以这样做:
def test(id,h={},*a) # do something with id # if not h.empty? then do something with h end # if not a.empty? then do something with a end end
以下是一些示例irb运行:
001 > def test (id, h={}, *a) 002?> puts id.inspect 003?> puts h.inspect 004?> puts a.inspect 005?> end => nil 006 > test(1,2,3,4) 1 2 [3, 4] => nil 007 > test(1,{"a"=>1,"b"=>2},3,4) 1 {"a"=>1, "b"=>2} [3, 4] => nil 008 > test(1,nil,3,4) 1 nil [3, 4] => nil
或许,我应该补充一下。 您可以将可选参数作为最后一个参数,但它必须是块/ proc。
例如:
def test(a,*b, &c) puts a.inspect puts b.inspect c.call if not c.nil? end
以下是一些示例调用:
006 > test(1,2,3) 1 [2, 3] => nil 007 > test(1,2,3) {puts "hello"} 1 [2, 3] hello => nil