这篇文章提供了有关Ruby中&参数的详细概述。
总结一下文章的内容,Ruby允许隐式和显式块。此外,Ruby还有块、Proc和Lambda。
当您调用:
def foo(block)
end
block
只是该方法的一个简单参数。该参数被引用为变量block
,您与其交互的方式取决于您传递的对象类型。
def foo(one, block, two)
p one
p block.call
p two
end
foo(1, 2, 3)
1
NoMethodError: undefined method `call' for 2:Fixnum
from (irb):3:in `foo'
from (irb):6
from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'
foo(1, Proc.new { 1 + 1 }, 3)
1
2
3
但是,当你在方法定义中使用“&”符号时,该块会呈现出不同的意义。你是在明确地定义一个接受块的方法。而且还会应用其他规则(例如每个方法不能有超过一个块)。
def foo(one, two, &block)
p one
p block.call
p two
end
首先,作为一个块,该方法签名现在接受“两个参数和一个块”,而不是“三个参数”。
foo(1, 2, Proc.new { "from the proc" })
ArgumentError: wrong number of arguments (3 for 2)
from (irb):7:in `foo'
from (irb):12
from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'
这意味着,您需要强制第三个参数成为一个块,并通过&符号传递参数。
foo(1, 2, &Proc.new { "from the proc" })
1
"from the proc"
2
然而,这种语法很少见。在 Ruby 中,通常使用
{}
来调用带有块的方法。
foo(1, 2) { "from the block" }
1
"from the block"
2
或者
do end
。
foo(1, 2) do
"from the block"
end
1
"from the block"
2
让我们回到该方法的定义中。我之前提到下面的代码是一个显式块声明。
def foo(one, two, &block)
block.call
end
方法可以隐式地接受一个块。隐式块通过 yield
调用。
def foo(one, two)
p yield
end
foo(1, 2) { "from the block" }
您可以使用
block_given?
来检查该块是否已传递。
def foo(one, two)
if block_given?
p yield
else
p "No block given"
end
end
foo(1, 2) { "from the block" }
=> "from the block"
foo(1, 2)
=> "No block given"
如果您将“block”声明为简单参数(因此没有&符号),则将无法使用与块相关的特性,因为它只是一个匿名方法参数。
shout_n_times(3) { shout.call }
或shout_n_times(3, &shout)
,因为它完全相同,但在第二个情况下不行,因为它正在等待一个参数! - Joel AZEMAR