10

我能够定义这样的方法:

def test(id, *ary, hash_params)
  # Do stuff here
end

但这使得hash_params论证是强制性的。这些也不起作用:

def t(id, *ary, hash_params=nil)  # SyntaxError: unexpected '=', expecting ')'
def t(id, *ary, hash_params={})   # SyntaxError: unexpected '=', expecting ')'

有没有办法让它成为可选的?

4

5 回答 5

13

ActiveSupport 中通过使用数组扩展对此提供了支持extract_options!

def test(*args)
  opts = args.extract_options!
end

如果最后一个元素是散列,那么它将从数组中弹出并返回,否则将返回一个空散列,这在技术上与您想要(*args, opts={})做的相同。

ActiveSupport 数组#extract_options!

于 2013-03-10T08:10:27.793 回答
11

你不能那样做。您必须考虑 Ruby 如何能够确定什么属于 *ary可选散列以及什么属于可选散列。由于 Ruby 无法读懂您的想法,因此上述参数组合(splat + 可选)无法从逻辑上解决。

你要么必须重新排列你的论点:

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.
于 2012-12-19T21:00:02.803 回答
4

除了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}

如果您的数组参数应在最后一个位置包含哈希,这将产生问题。

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}]  {}
于 2012-12-19T21:09:42.450 回答
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]
于 2012-12-19T22:22:52.743 回答
1

@Casper 是对的。只有一个参数可以有 splat 运算符。参数首先从左到右分配给非喷溅参数。剩余的参数被分配给 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

也许,我应该补充一下。你可以有一个可选参数作为最后一个参数,但它必须是一个块/过程。

例如:

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 
于 2012-12-19T21:05:24.027 回答