不,它没有。作为 Ruby 的一般规则,如果两件事看起来很相似,那么您可以打赌它们之间存在细微的差别,这使得它们中的每一个都是独一无二且必要的。
{ 和 } 并不总是充当块分隔符的角色。当它们不充当块分隔符时(例如在构造哈希时,{ a: 1, b: 2 }),它们不能被do...end替换。但是当花括号确实分隔了一个块时,它们几乎总是可以替换为do ... end。但要小心,因为有时这会改变你陈述的意思。这是因为{ ... } 具有更高的优先级,它们比do ... end 绑定更紧密:
puts [ 1, 2, 3 ].map { |e| e + 1 } # { ... } bind with #map method
2
3
4
#=> nil
puts [ 1, 2, 3 ].map do |e| e + 1 end # do ... end bind with #puts method
#<Enumerator:0x0000010a06d140>
#=> nil
至于相反的情况,do ... end 在块分隔符的作用下不能总是用大括号代替。
[ 1, 2, 3 ].each_with_object [] do |e, obj| obj << e.to_s end # is possible
[ 1, 2, 3 ].each_with_object [] { |e, obj| obj << e.to_s end # invalid syntax
在这种情况下,您必须将有序参数括起来:
[ 1, 2, 3 ].each_with_object( [] ) { |e, obj| obj << e.to_s } # valid with ( )
这些句法规则的结果是你可以这样写:
[ 1, 2, 3 ].each_with_object [ nil ].map { 42 } do |e, o| o << e end
#=> [ 42, 1, 2, 3 ]
上面还演示了{}不能被do/end替换的情况:
[ 1, 2, 3 ].each_with_object [ nil ].map do 42 end do |e, o| o << e end
#=> SyntaxError
与 -> 的 Lambda 语法略有不同,因为它同样接受两者:
foo = -> x do x + 42 end # valid
foo = -> x { x + 42 } # also valid
此外,do 和 end 本身并不总是分隔块。特别是这个
for x in [ 1, 2, 3 ] do
puts x
end
还有这个
x = 3
while x > 0 do
x -= 1
end
还有这个
x = 3
until x == 0 do
x -= 1
end
表面上包含do ... end 关键字,但它们之间并没有真正的块。它们里面的代码并没有引入新的范围,它只是用于重复一些语句的语法。这里不能使用大括号,语法可以不写do,如:
for x in [ 1, 2, 3 ]
puts x
end
# same for while and until
对于{...} 和do...end 分隔符可互换的情况,使用哪个分隔符的选择取决于编程风格,并且是extensively discussed in another question(来自我在这里举了我的一个例子,我接受了谁的答案)。在这种情况下,我个人的偏好是强调可读性而不是严格的规则。