优先级规则
花括号内的块比 do
和 end
中的块具有更高的优先级(precedence)。让我们看看这在实践中意味着什么。思考这两个例子:
foo bar do |s| puts( s ) end
foo bar{ |s| puts(s) }
这里,foo
和 bar
是方法。那么块传递给哪个方法?事实证明,do..end
块将被传递给最左边的方法 foo
,而花括号中的块将被发送到最右边的方法 bar
。这是因为花括号具有更高的优先级。思考这个程序…
precedence.rb
def foo( b )
puts("---in foo---")
a = 'foo'
if block_given?
puts( "(Block passed to foo)" )
yield( a )
else
puts( "(no block passed to foo)" )
end
puts( "in foo, arg b = #{b}" )
return "returned by " << a
end
def bar
puts("---in bar---")
a = 'bar'
if block_given?
puts( "(Block passed to bar)" )
yield( a )
else
puts( "(no block passed to bar)" )
end
return "returned by " << a
end
foo bar do |s| puts( s ) end # 1) do..end block
foo bar{ |s| puts(s) } # 2) {..} block
这里 do..end
块的优先级较低,方法 foo
优先。这意味着 bar
和 do..end
块都传递给 foo
。因此,这两个表达式是等价的:
foo bar do |s| puts( s ) end
foo( bar ) do |s| puts( s ) end
另一方面,花括号块具有更高的优先级,因此它尝试立即执行并传递给第一个可能的接收方法 (bar)
。然后将结果(即 bar
返回的值)作为参数传递给 foo
;但这一次,foo
本身并没有收到块。因此,以下两个表达式是等效的:
foo bar{ |s| puts(s) }
foo( bar{ |s| puts(s) } )
如果你对这一切感到困惑,不要难过因为实际上并不是你一个人感到困惑!Ruby 块的行为远非透明的。潜在的歧义是由于在 Ruby 中参数列表周围的括号是可选的。从上面给出的替代版本中可以看出,当使用括号时,模糊性消失了。
提示…
一个方法可以使用block_given?
方法测试它是否已经收到一个块。你可以在 precedence.rb 程序中找到相关示例。