Ruby 读“do”和“end”的方式与“{”和“}”相同吗?

Mic*_*ail 5 ruby syntax lambda block

在 Ruby 中编写块有两种不同的语法。有

do |something|
    ...
end
Run Code Online (Sandbox Code Playgroud)

还有

{ |something|
    ...
}
Run Code Online (Sandbox Code Playgroud)

我意识到这只是用括号替换关键字“do”和“end”。这让我想知道,当 Ruby 使用这两种语法时,处理它们的方式是否有任何显着差异。或者 Ruby 是否以相同的方式处理它们,可以互换?如果它们完全可以互换,那么为什么要同时包含两者呢?

Bor*_*cky 9

不,事实并非如此。作为 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
Run Code Online (Sandbox Code Playgroud)

至于相反的情况,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 }   # invalid syntax
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您必须将有序参数括起来:

[ 1, 2, 3 ].each_with_object( [] ) { |e, obj| obj << e.to_s }  # valid with ( )
Run Code Online (Sandbox Code Playgroud)

这些语法规则的结果是你可以这样写:

[ 1, 2, 3 ].each_with_object [ nil ].map { 42 } do |e, o| o << e end
#=> [ 42, 1, 2, 3 ]
Run Code Online (Sandbox Code Playgroud)

上面还演示了{}不可被do/替换的情况end

[ 1, 2, 3 ].each_with_object [ nil ].map do 42 end do |e, o| o << e end
#=> SyntaxError
Run Code Online (Sandbox Code Playgroud)

Lambda 语法->略有不同,它同样接受两者:

foo = -> x do x + 42 end  # valid
foo = -> x { x + 42 }     # also valid
Run Code Online (Sandbox Code Playgroud)

此外,doend本身并不总是界定一个块。特别是,这

for x in [ 1, 2, 3 ] do
  puts x
end
Run Code Online (Sandbox Code Playgroud)

和这个

x = 3
while x > 0 do
  x -= 1
end
Run Code Online (Sandbox Code Playgroud)

和这个

x = 3
until x == 0 do
  x -= 1
end
Run Code Online (Sandbox Code Playgroud)

表面上包含do...end关键字,但它们之间没有真正的障碍。它们内部的代码没有引入新的作用域,它只是用于重复一些语句的语法。这里不能使用大括号,语法可以不使用do,例如:

for x in [ 1, 2, 3 ]
  puts x
end

# same for while and until
Run Code Online (Sandbox Code Playgroud)

{对于...}do...分隔符可以互换的情况end,选择使用哪个分隔符是编程风格的问题,并且在另一个问题中进行了广泛讨论(我从其接受的答案中获取了一个示例)。在这种情况下,我个人的偏好是强调可读性而不是严格的规则。