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

发布于 2024-08-30 21:27:35 字数 1651 浏览 2 评论 0原文

以下问题与问题“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()

这么说,没有办法让它直接工作,用下面2种方式:

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,它可以工作吗?

The following question is related to the question "Ruby Print Inject Do Syntax". My question is, can we insist on using do and end and make it work with puts or p?

This works:

a = [1,2,3,4]

b = a.inject do |sum, x|
  sum + x
end
puts b   # prints out 10

so, is it correct to say, inject is an instance method of the Array object, and this instance method takes a block of code, and then returns a number. If so, then it should be no different from calling a function or method and getting back a return value:

b = foo(3)
puts b

or

b = circle.getRadius()
puts b

In the above two cases, we can directly say

puts foo(3)
puts circle.getRadius()

so, there is no way to make it work directly by using the following 2 ways:

a = [1,2,3,4]

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

but it gives

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

grouping the method call using ( ) doesn't work either:

a = [1,2,3,4]

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

and this gives:

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)
         ^

finally, the following version works:

a = [1,2,3,4]

puts a.inject { |sum, x|
    sum + x
}

but why doesn't the grouping of the method invocation using ( ) work in the earlier example? What if a programmer insist that he uses do and end, can it be made to work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烟燃烟灭 2024-09-06 21:27:35

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

a = [1,2,3,4]

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

From the (unofficial) ruby grammar, we see that the contents of (...) in puts (...) must be CALL_ARGS, which don't directly reduce to STMT. However, they can reduce to '(' COMPSTMT ')'. By including an extra set of parentheses, you can use do ... end.

a = [1,2,3,4]

puts ((a.inject do |sum, x| 
         sum + x   
       end))
春夜浅 2024-09-06 21:27:35

这里的问题不仅仅是括号:它主要是括号之后放置之前的空格。

通过代码,

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:警告:(...) 解释为分组表达式

语法正确

ruby -cw 用于C 在打开完整的警告警告的情况下检查语法。当 -cw 启用时,您将收到关于可疑括号和分组的警告。我更习惯看到的错误是“不要在参数括号前添加空格”——所以也不要这样做!

最后,a.inject do 在没有括号的情况下失败,但 a.inject { 有效,原因是大括号的优先级高于 do/<代码>结束。作为一个非常粗略的指导方针,您可以说 p a.map { foo } 相当于 p(a.map do foo end) ;并且 p a.map do foo end 相当于 (p a.map) do foo end,当然它不接受块参数。

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

块、闭包和过程

块/关闭

  • 块必须遵循方法调用:

调用 do ... end

调用 { ... }

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

The issue here isn't just your parentheses: it's primarily the space after puts before the parentheses.

With the code

a = [1,2,3,4]

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

We get the syntax errors you listed in the question.

If you drop the space after puts,

a = [1,2,3,4]

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

prints out 10 as expected.

Finally, using puts ((a.inject... with the space and double parentheses also prints out 10, but running that through ruby -cw XXX.rb tells us:

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

Syntax OK

ruby -cw is used to Check the syntax with full Warnings turned on. When -cw is on, you will be warned about dubious parentheses and grouping. The error I'm more used to seeing is "don't put space before argument parentheses" -- so don't do that either!

Lastly, the reason a.inject do fails without parentheses but a.inject { works, is that braces have a higher precedence than do/end. As a very rough guideline, you could say that p a.map { foo } is equivalent to p(a.map do foo end); and p a.map do foo end is equivalent to (p a.map) do foo end, which of course does not take a block argument.

See also the Ruby quick reference on blocks (particularly the last two lines):

Blocks, Closures, and Procs

Blocks/Closures

  • blocks must follow a method invocation:

invocation do ... end

invocation { ... }

  • Blocks remember their variable context, and are full closures.
  • Blocks are invoked via yield and may be passed arguments.
  • Brace form has higher precedence and will bind to the last parameter if invocation made w/o parens.
  • do/end form has lower precedence and will bind to the invocation even without parens.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文