【问题标题】:In Ruby, why is a method invocation not able to be treated as a unit when "do" and "end" is used?在Ruby中,为什么在使用“do”和“end”时不能将方法调用视为一个单元?
【发布时间】:2011-02-15 07:24:02
【问题描述】:

以下问题与问题“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 怎么办?

【问题讨论】:

  • inject 实际上是一个实例方法。
  • 啊,没错,调用来触摸实例的值/属性的方法应该是实例方法。
  • 谢谢马修,有问题已更正。
  • 我不明白你为什么要写这么一个巨大的哲学问题,而真正的问题只是一个优先级问题

标签: ruby syntax function methods


【解决方案1】:

从(非官方的)ruby grammar可以看出puts (...)(...)的内容必须是CALL_ARGS,而不是直接归约为STMT。但是,它们可以减少到'(' COMPSTMT ')'。通过包含一组额外的括号,您可以使用do ... end

a = [1,2,3,4]

puts ((a.inject do |sum, x| 
         sum + x   
       end))

【讨论】:

  • 它确实有效。起初我可能觉得它很奇怪,因为 Ruby 的括号有时是可选的。此外,有 2 套 ( ) 可能会脱落,如果一对不起作用,请添加额外的一对。
【解决方案2】:

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

有代码

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 用于在打开完整的 Warnings 的情况下C检查语法。当-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 quick reference on blocks(特别是最后两行):

块、闭包和过程

阻塞/关闭

  • 块必须跟在方法调用之后:

invocation do ... end

invocation { ... }

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

【讨论】:

    猜你喜欢
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 2017-05-17
    • 2010-09-24
    相关资源
    最近更新 更多