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

时间:2016-06-03 11:32:28

标签: 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)。)

3 个答案:

答案 0 :(得分:15)

简短回答

因为这是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 parsing rules (pseudo-BNF)or可以很好地使用ruby的可选括号。

简而言之,参数列表(CALL_ARGS)是ARG的列表,以逗号分隔。现在,大多数东西都是ARG(类定义,例如,通过作为PRIMARY),但不是简单的EXPR。如果用括号括起表达式,那么它将匹配"复合语句"的规则。因此,将是一个主要的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`

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

BONUS:类定义为有效ARG

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

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

答案 1 :(得分:10)

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

{puts(nil} or {4)}

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

puts(nil

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

4)

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

puts((nil or 4))

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

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

puts (nil or 4)

答案 2 :(得分:7)

@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(见上文提到的PRIMARY)。