我相信可能让您感到困惑的是 Procs 的一些属性。如果给他们一个数组参数,他们会自动 splat。此外,ruby 块通常有一些有趣的方法来处理块参数。您期望的行为是您将使用 Lambda 获得的行为。我建议阅读Proc.lambda?文档并在使用数组调用 ruby 块时要小心。
现在,让我们从 splat 运算符开始,然后转到 ruby 如何处理块参数:
def foo(a, b, *c)
c.map { |i| i * b } # Prefer to use map alias over collect
end
foo([1, 2, 3, 4]) # `block in <main>': wrong number of arguments (given 1, expected 2+) (ArgumentError)
foo(*[1, 2, 3, 4]) # works as expected
因此,在您的论点错误中,这是有道理的:def foo()
至少需要两个参数:a
, b
,以及带有*c
. 是splat 运算*
符。它会将数组转换为单个参数,或者在相反的情况下,将可变数量的参数转换为数组。因此,当您说 时,您是在给出一个论点,并且它是。您没有设置或。例如,什么会起作用,因为您正在设置,和。这将是同一件事:.foo([1,2,3,4])
foo
a
[1,2,3,4]
b
*c
foo(1, 1, 1, 2, 3, 4])
a
b
c
foo(1, 1, *[1,2,3,4])
现在foo(*[1, 2, 3, 4])
可以按预期工作,因为 splat 运算符 ( *
) 正在将其转换为foo(1, 2, 3, 4)
或等效地foo(1, 2, *[3, 4])
好的,现在我们已经涵盖了 splat 运算符,让我们回顾一下下面的代码(我做了一些小的改动):
a_proc = Proc.new { |a, b, *c| c.map { |i| i * b }}
a = [1, 2, 3, 4]
puts a_proc.call(a)
puts a_proc.call(*a)
请记住,如果块/procs 被赋予单个array
参数,它们将自动splat
使用它。因此,如果您有一个数组数组arrays = [[1, 1], [2, 2], [3, 3]]
并且您这样做了,arrays.each { |a, b| puts "#{a}:#{b}" }
那么您将得到1:1
, 2:2
, 和3:3
作为输出。当每个元素作为参数传递给块时,它会看到它是一个数组并对其进行分解,将元素分配给尽可能多的给定块变量。而不是仅仅把那个数组放在a
比如 中a = [1, 1]; b = nil
,你会得到a = 1; b = 1
. 它对 proc 做同样的事情。
a_proc.call([1, 2, 3, 4])
变成Proc.new { |1, 2, [3, 4]| c.map { |i| i * b }}
并将输出[6, 8]
。它会自动拆分它自己的参数。