在 Ruby 中,为什么当“do”时方法调用不能被视为一个单元?和“结束”被使用?
以下问题与问题“Ruby Print Inject Do Syntax”相关。我的问题是,我们可以坚持使用 do
和 end
并使其与 puts
或 p
一起使用吗?
这是可行的:
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
}
但是为什么使用 对方法调用进行分组( )
在前面的示例中起作用吗?如果程序员坚持使用do
和end
,它可以工作吗?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
从(非官方)ruby 语法,我们看到
(...)puts (...)
中的 code> 必须是CALL_ARGS
,它不会直接简化为STMT
。但是,它们可以简化为'(' COMPSTMT ')'
。通过包含一组额外的括号,您可以使用do ... end
。From the (unofficial) ruby grammar, we see that the contents of
(...)
inputs (...)
must beCALL_ARGS
, which don't directly reduce toSTMT
. However, they can reduce to'(' COMPSTMT ')'
. By including an extra set of parentheses, you can usedo ... end
.这里的问题不仅仅是括号:它主要是括号之后
放置
之前的空格。通过代码,
我们得到了您在问题中列出的语法错误。
如果在
puts
之后删除空格,则会按预期打印出
10
。最后,使用
puts ((a.inject...
以及空格和双括号 也 打印出10
,但通过ruby -cw XXX.rb
告诉我们: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 快速参考(特别是最后两行) :
The issue here isn't just your parentheses: it's primarily the space after
puts
before the parentheses.With the code
We get the syntax errors you listed in the question.
If you drop the space after
puts
,prints out
10
as expected.Finally, using
puts ((a.inject...
with the space and double parentheses also prints out10
, but running that throughruby -cw XXX.rb
tells us: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 buta.inject {
works, is that braces have a higher precedence thando
/end
. As a very rough guideline, you could say thatp a.map { foo }
is equivalent top(a.map do foo end)
; andp 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):