为什么表达式 (true == true == true) 会产生语法错误?

65

Ruby

true == true == true

语法错误,意外的 tEQ

JavaScript 相比:

true == true == true
// => true
vs. C:
1 == 1 == 1
// => 1

2
有趣的是,似乎只有相等运算符(=====!=)会这样做。即使 <> 解析正确,也会像你预期的那样产生运行时错误。此外,我能找到的唯一来源声称具有 Ruby 的完整语法的资料都表明这种语法是允许的。 - Silvio Mayolo
2
它也可以像这样不带括号工作,使用显式调用,true .== true .== true - potashin
4
我不知道有多少其他人不太相信地将失败的代码输入到irb中,期望得到不同的结果? - Brad Werth
在答案中,==被列为非结合的(A=N),这意味着这样的X==Y==Z表达式是无效的(结合性是“在相同优先级的运算符周围添加隐式括号”的内容)。问题中有许多链接可能会返回到更“官方的来源”,可以干净地引用。(这个问题或多或少是关于该问题/答案中语法规则的特定子集/应用程序。) - user2864740
@SilvioMayolo 语法的“为什么”通常是离题的 :) 不过,一个实用的语法示例,尽管如果存在结合性则不起作用(即非结合性允许通过删除其他歧义来形成此其他构造形式),但看到它会很有趣。 - user2864740
显示剩余2条评论
3个回答

49

对于==方法、===方法、!=方法、=~方法和<=>方法,关联方向未定义,这些方法具有相同的优先级并形成一个单独的优先级组。

文档

因此,在链式使用多个上述操作符时,应该通过以下任一方式显式设置其计算顺序:

  • 圆括号 ()

    (true == true) == true # => true
    true == (true == true) # => true
    
  • 或点运算符.(最后一个等式检查可以省略):

  • true .== true == true # => true
    

1
我很想知道为什么,但我认为这超出了问题和你的回答的范围。 - Cary Swoveland
13
也许是因为在Ruby中,如果把==左结合的话,1 == 1 == 1会被计算为false,这可能会导致几个bug。而且这也没有什么意义——第三个运算数的唯一合理值是truefalse,即a == b == truea == b == false,它们可以表示为a == ba != b - Stefan
2
@Stefan:只有一个情况可以这样使用,而且我必须说这个例子有点牵强:在自定义类中可以覆盖==操作符,从而使相等性检查返回的不仅仅是truefalse(例如, nil)。 - potashin
3
@CarySwoveland 我认为可以从语言设计师的角度解决这个问题,像这样 - Rrr Rrr
JavaScript中真值在布尔值和数字比较中的应用,为什么我们都应该停止在JavaScript示例中使用0或1来比较整数或布尔值。 - Arye Eidelman

7

简而言之,语法意味着所有三个值都相等,但在JavaScript或C中并非如此,因此通过Ruby给出语法错误,为将来实现打开了大门。

如果我正确理解问题,value_a == value_b == value_c仅当它们都使用“==”作为比较运算符时才返回true,如此方法所示,只有在它们都相等时才会返回true。

# version 1
def compare_3_values(a, b, c)
  a == b && a == c && b == c
end

然而,还有另一个可能的预期结果。要按照先前答案中所示实施此操作:

#version 2
def compare_3_values(a, b, c)
  (a == b) == c
end

结果截然不同。
JavaScript始终使用第二版,这相当无用,因为第三个项目始终与true或false进行比较(如果第三个项目是整数,则为0或1),这就是为什么false == false == true返回true的原因。

好消息是,由于Ruby会出现语法错误,它是唯一可以在不破坏所有代码的情况下实现此功能的语言。

对于任何其他语言,它都会破坏大量代码,即使它在以后的主要版本中实现了,也需要有一个标志/设置来打开或关闭多年,因此这永远不值得。

Ruby中的一些有趣结果。
false .== false == true
=> true

false .== true == false
=> true

true .== false == false
=> true

false .== false == false
=> false

true .== true == false
false

在JavaScript中,
false == false == true
=> true

false == true == false
=> true

true == false == false
=> true

false == false == false
=> false

true == true == false
=> false

Edit 也在 C 中进行了测试,其作用类似于 JavaScript,在将前两个值的结果与第三个值进行比较时表现相同。


4

第一个答案很好,但为了避免仍然有人不完全清楚(并且会问为什么),这里提供几个例子。


C语言中,==运算符是从左到右结合的,布尔值用1(true)和0(false)表示,所以第一个1 == 1计算结果为1(true),然后再将第一个表达式的结果与第二个进行比较。你可以尝试:

2 == 2 == 2 // => 0

在C语言中,它的计算方式为:
(2 == 2) == 2
1 == 2 // => 0

在 JavaScript 中,与 C 类似,== 是从左到右结合的。这次我们尝试使用数字 0(虽然同样的 C 示例也可以工作):
0 == 0 == 0
false

再来一遍:

0 == 0 == 0
true == 0 // => false

在Ruby中,== 不具有关联性,即它不能在单个表达式中多次使用,因此无法评估该表达式。为什么做出这样的决定是语言作者需要回答的问题。此外,Ruby不将数字1定义为布尔值,因此1 == true的结果为false。

第二个答案指出,在Ruby中存在一些“奇怪”的情况,但它们都能按预期进行评估:

(1 == 1) == 1
true == 1 # => false

1 == (1 == 1)
1 == true # => false

1 .== 1 == 1
(1 == 1) == 1
true == 1 # => false

false .== false == true
(false == false) == true
true == true # => true

false .== true == false
(false == true) == false
false == false # => true

true .== false == false
(true == false) == false
false == false # => true

false .== false == false
(false == false) == false
true == false # => false

true .== true == false
(true == true) == false
true == false # => false

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接