为什么带有splat参数的Ruby procs / blocks的行为与方法和lambda不同?

时间:2014-05-30 01:11:58

标签: ruby lambda block proc splat

为什么Ruby(2.0)使用splat参数处理/块的行为与方法和lambdas不同?

def foo (ids, *args)
  p ids
end
foo([1,2,3]) # => [1, 2, 3]

bar = lambda do |ids, *args|
  p ids
end
bar.call([1,2,3]) # => [1, 2, 3]

baz = proc do |ids, *args|
  p ids
end
baz.call([1,2,3]) # => 1

def qux (ids, *args)
  yield ids, *args
end
qux([1,2,3]) { |ids, *args| p ids } # => 1

这是对此行为的确认,但没有说明: http://makandracards.com/makandra/20641-careful-when-calling-a-ruby-block-with-an-array

2 个答案:

答案 0 :(得分:1)

有两种类型的Proc对象:lambda以与普通方法相同的方式处理参数列表,proc使用" tricks" (Proc#lambda?)。 proc如果数组是唯一的参数,则会展开数组,忽略额外的参数,将nil分配给缺失的数组。您可以使用解构来部分模仿proc lambda行为:

->((x, y)) { [x, y] }[1]         #=> [1, nil]
->((x, y)) { [x, y] }[[1, 2]]    #=> [1, 2]
->((x, y)) { [x, y] }[[1, 2, 3]] #=> [1, 2]
->((x, y)) { [x, y] }[1, 2]      #=> ArgumentError

答案 1 :(得分:0)

刚遇到类似的问题!

无论如何,我的主要内容是:

  1. splat运算符以可预测的方式用于数组赋值

  2. Procs有效地为输入分配参数(参见下面的免责声明)

  3. 这会导致奇怪的行为,即上面的例子:

    baz = proc do |ids, *args|
      p ids
    end
    baz.call([1,2,3]) # => 1
    

    那么发生了什么? [1,2,3]传递给baz,然后将数组分配给其参数

    ids, *args = [1,2,3]
    ids = 1
    args = [2,3]
    

    运行时,该块只会检查ids1。实际上,如果您将p args插入块中,您会发现它确实是[2,3]。当然不是人们对方法(或lambda)的期望。

    免责声明:我无法确定Procs是否只是将其参数分配给引擎下的输入。但它似乎与他们不强制执行正确数量的参数的行为相匹配。事实上,如果你给Proc太多的论点,它会忽略额外的东西。太少了,它通过了nils。完全像变量赋值。