为什么`put(nil或4)`在Ruby中失败?

当我做:

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

简短的回答

因为这就是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 

因为ruby 解析规则(伪BNF) ,所以在这里or与ruby的可选括号很好地协作 。

简而言之,参数列表(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 

这是因为or和优先级低于方法调用。 您的表达式被解释为:

 {puts(nil} or {4)} 

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

 puts(nil 

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

 4) 

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

 puts((nil or 4)) 

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

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

 puts (nil or 4) 

@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,反过来,分支到'(' 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调用的命令,它扩展为OPERATION CALL_ARGS ,这意味着ARG是“(1或2)”,这是一个有效的 ARG(参见上面提到的PRIMARY)。