在Ruby中,为什么在使用“do”和“end”时,方法调用不能被视为一个单元?

以下问题与“ Ruby Print Inject Do Syntax ”问题有关。 我的问题是,我们可以坚持使用doend并使其与putsp吗?

这有效:

 a = [1,2,3,4] b = a.inject do |sum, x| sum + x end puts b # prints out 10 

所以,是正确的说, inject是Array对象的实例方法,这个实例方法接受一段代码,然后返回一个数字。 如果是这样,那么它应该与调用函数或方法并返回返回值没有什么不同:

 b = foo(3) puts b 

要么

 b = circle.getRadius() puts b 

在以上两种情况下,我们可以直接说

 puts foo(3) puts circle.getRadius() 

因此,无法通过以下两种方式直接使其工作:

 a = [1,2,3,4] puts a.inject do |sum, x| sum + x end 

但它给了

 ch01q2.rb:7:in `inject': no block given (LocalJumpError) from ch01q2.rb:4:in `each' from ch01q2.rb:4:in `inject' from ch01q2.rb:4 

使用( )对方法调用进行分组也不起作用:

 a = [1,2,3,4] puts (a.inject do |sum, x| sum + x end) 

这给了:

 ch01q3.rb:4: syntax error, unexpected kDO_BLOCK, expecting ')' puts (a.inject do |sum, x| ^ ch01q3.rb:4: syntax error, unexpected '|', expecting '=' puts (a.inject do |sum, x| ^ ch01q3.rb:6: syntax error, unexpected kEND, expecting $end end) ^ 

最后,以下版本有效:

 a = [1,2,3,4] puts a.inject { |sum, x| sum + x } 

但是为什么使用( )的方法调用分组在前面的例子中不起作用? 如果程序员坚持他使用doend ,它可以被用来工作吗?

从(非官方) ruby语法中 ,我们看到puts (...)中的puts (...)必须是CALL_ARGS ,它们不会直接缩减为STMT 。 但是,它们可以缩减为'(' COMPSTMT ')' 。 通过包含一组额外的括号,您可以使用do ... end

 a = [1,2,3,4] puts ((a.inject do |sum, x| sum + x end)) 

这里的问题不仅仅是你的括号:它主要是puts括号之后的空格。

随着代码

 a = [1,2,3,4] puts (a.inject do |sum, x| sum + x end) 

我们得到您在问题中列出的语法错误。

如果你放弃之后puts空间,

 a = [1,2,3,4] puts(a.inject do |sum, x| sum + x end) 

按预期打印10

最后,使用puts ((a.inject...带空格和双括号打印出10 ,但通过ruby -cw XXX.rb运行它告诉我们:

a.rb:5: warning: (...) interpreted as grouped expression

Syntax OK

ruby -cw用于在打开完整的W arnings时查看语法。 当-cw打开时,您将收到有关可疑括号和分组的警告。 我更习惯看到的错误是“不要在参数括号之前放置空格” – 所以不要这样做!

最后, a.inject do没有括号但是a.inject {工作的情况下失败的原因是,大括号的优先级高于do / end 。 作为一个非常粗略的准则,你可以说p a.map { foo }等同于p(a.map do foo end) ; 和p a.map do foo end相当于(p a.map) do foo end ,这当然不带块参数。

另请参阅块上的Ruby快速参考 (特别是最后两行):

块,闭包和过程

块/瓶盖

  • 块必须遵循方法调用:

invocation do ... end

invocation { ... }

  • 块记住它们的变量上下文,并且是完全闭包。
  • 块通过yield调用,可以传递参数。
  • Brace表单具有更高的优先级,如果调用没有parens,则将绑定到最后一个参数。
  • do / end表单具有较低的优先级,即使没有parens也会绑定到调用。