【问题标题】:Why does `puts(nil or 4)` fail in Ruby?为什么 Ruby 中的 puts(nil or 4) 会失败?
【发布时间】:2016-06-03 11:32:28
【问题描述】:

当我这样做时:

puts(nil or 4)

Ruby 抱怨:

SyntaxError: syntax error, unexpected keyword_or, expecting ')'

这是为什么呢? puts(nil || 4) 确实有效,但我想知道为什么 or 没有。我认为两者之间的区别仅在于它们的运算符优先级。

(我知道表达式nil or 4 似乎没什么用,因为它总是返回4。为了简单起见,这只是一个示例。我的实际表达式是Integer(ENV['WD'] or 4)。)

【问题讨论】:

  • 奇怪的是,puts (nil or 4) 工作正常 - 在put 之后放置了一个空格
  • 好像是个bug)
  • 如果是bug,and也有同样的bug。
  • puts((nil or 4)) 也有效!?!
  • @DaveSchweisguth:看我的回答 :)

标签: ruby


【解决方案1】:

简答

因为 ruby​​ 语法就是这样。

更长的答案

and/or 关键字被设计用于控制流结构。考虑这个例子:

def die(msg)
  puts "Exited with: #{msg}"
end

def do_something_with(arg)
  puts arg
end

do_something_with 'foo' or die 'unknown error'
# >> foo
# >> Exited with: unknown error

这里 or 与 ruby​​ 的可选括号配合得很好,因为 ruby​​ parsing rules (pseudo-BNF)

简而言之,参数列表 (CALL_ARGS) 是一个 ARG 列表,以逗号分隔。现在,大多数东西都是 ARG(类定义,例如,通过成为 PRIMARY),但不是朴素的 EXPR。如果你用括号括住一个表达式,那么它将匹配“复合语句”的规则,因此将是一个 PRIMARY,它是一个 ARG。这是什么意思

puts( (nil or 4) ) # will work, compound statement as first argument
puts (nil or 4)  # same as above, omitted optional method call parentheses
puts(nil or 4) # will not work, EXPR can't be an argument
puts nil or 4 # will work as `puts(nil) or 4`

您可以阅读上面引用的语法以了解确切它是如何工作的。

奖励:类定义是有效 ARG 的示例

puts class Foo
       def bar
         puts "hello"
       end
     end, 'second argument'

# >> bar # this is the "value" of the class definition
# >> second argument

【讨论】:

  • 很好的解释!
  • 啊,我明白了。 andor 具有它们的优先级,因为它们没有明确定义为 ARG。这么多运算符被确定为 ARG,很容易认为 ARG 和 EXPR 是相同的。讨厌。我认为如果没有andor,我们会过得更好。
  • @DaveSchweisguth:是的,完全正确。我从不使用它们。 :)
  • @DaveSchweisguth 风格指南建议不要使用它们。 github.com/bbatsov/ruby-style-guide#no-and-or-or
  • 至于样式指南@SteveTurczyn 链接到:为了浏览器与 github 的 JavaScript 锚不兼容的用户的利益(我使用的是“旧”Opera 浏览器):您可以搜索句子“和和或关键字被禁止”的长页到达相关部分。
【解决方案2】:

这是因为orand 的优先级低于方法调用。你的表达被解释为:

{puts(nil} or {4)}

其中{} 代表分组。语法错误来自表达式

puts(nil

(以下也会引发语法错误):

4)

如果您通过在表达式周围放置一对括号来强制分组,那么它将按照您的预期方式工作:

puts((nil or 4))

请注意,外面的一对括号用于方法调用,而不是分组,因此只有一对括号不会改变分组。

或者,如果您通过放置一个空格来消除用于分组的一对括号的歧义,那么这也可以:

puts (nil or 4)

【讨论】:

    【解决方案3】:

    @Sergio Tulentsev(和@sawa)给出了一个很好的答案,但我想重新措辞一下,以便将来能快速理解:

    Ruby 允许我们在函数调用中去掉括号。也就是说,而不是:

    func1(ARG, ARG, ARG) or func2(ARG, ARG, ARG)
    

    我们可以做到:

    func1 ARG, ARG, ARG or func2 ARG, ARG, ARG
    

    但是,为了使最后一行的行为与第一行一样,“或”不能是用于 ARG 顶层的运算符(否则最后一行将被解释为func1(ARG, ARG, ARG or func2 ARG, ARG, ARG))。事实上,当我们查看BNF 时,我们看到 ARG 没有直接提到“或”/“和”(这意味着它在那里是非法的)。

    但是 ARG 仍然可以使用“或”:通过将表达式括在括号中。在 BNF 中,我们将其视为 ARG 可以分支到的 PRIMARY 替代方案(作为 PRIMARY,反过来,分支到 '(' COMPSTMT ')')。

    现在,至于为什么 func (1 or 2)func((1 or 2)) 有效,而 func(1 or 2) 无效:

    • func(1 or 2) 是 BNF 所称的 FUNCTION,它扩展为 OPERATION ['(' [CALL_ARGS] ')'],这意味着 ARG 是“1 或 2”,但是,正如我们所见,ARG 不能包含“或” ,所以它是无效的

    • func((1 or 2)) 又是OPERATION ['(' [CALL_ARGS] ')'],但这里的 ARG 是“(1 或 2)”,这是一个 有效 ARG(参见上面提到的 PRIMARY)。

    • func (1 or 2) 是 BNF 所称的 COMMAND,它扩展为 OPERATION CALL_ARGS,这意味着 ARG 是“(1 或 2)”,这是一个 有效 ARG(参见上面提到的主要)。

    【讨论】:

    • 用额外的推理很好地总结了其他答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 2012-02-18
    • 2012-02-13
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    相关资源
    最近更新 更多