如何使用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