8

为什么带有 splat 参数的 Ruby (2.0) 过程/块的行为与方法和 lambda 不同?

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

4

2 回答 2

2

有两种类型的Proc对象:lambda以与普通方法相同的方式处理参数列表,以及proc使用“技巧”(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
于 2014-05-31T13:08:49.083 回答
1

刚遇到类似的问题!

无论如何,我的主要收获:

  1. splat 运算符以可预测的方式进行数组分配

  2. Procs 有效地将参数分配给输入(请参阅下面的免责声明)

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

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]

运行时,该块仅检查ids,即1. 事实上,如果你插入p args到块中,你会发现它确实是[2,3]. 当然不是人们期望从方法(或 lambda)得到的结果。

免责声明:我不能确定 Procs 是否只是将他们的参数分配给引擎盖下的输入。但这似乎与他们不强制执行正确数量的参数的行为相匹配。事实上,如果你给一个 Proc 的参数太多,它会忽略额外的参数。太少了,它以零通过。就像变量赋值一样。

于 2014-06-12T22:33:46.203 回答