【问题标题】:Precedence of the operators & and | in Scala运算符 & 和 | 的优先级在斯卡拉
【发布时间】:2013-09-26 08:08:09
【问题描述】:

在“Scala 编程”一书(Martin Odersky,第 2 版)中,他们给出了这个运算符优先级表此处不完整):

* / %
+ -
:
= !
< >
&
^
|

因此,如果一个运算符的第一个字符在此表中的位置高于另一个运算符的第一个字符,则先计算前一个运算符。

根据该代码应该打印出yy,但它会打印出x

def x() = { print('x'); true }
def y() = { print('y'); true }

x || y && y        // prints `x` but should `yy`

我的理解是,如果&在表中比|高,必须先求值。就像 * 优先于 +,所以在x + y * y 中,最后一条语句首先被求值。


编辑

也看看这段代码

def x() = { print('x'); 1 }
def y() = { print('y'); 3 }

x == x + y * y        // xxyy

看起来它从左到右评估它们,但根据表格“解决”它们。

【问题讨论】:

  • 因为在第二种情况下 xy 结果为 Int 并且在布尔值的情况下它使用不同的评估模型
  • ||| 不同,并且本书没有给出逻辑操作数的优先级。我假设在&amp;&amp; 仍然高于|| 的Java 中使用相同的优先级,但是这里的工作存在短路。 Java 也会打印“x”。

标签: scala


【解决方案1】:

原始版本:

x || y && y

应用优先级:

x || (y && y)

(注意,如果优先级颠倒,则为(x || y) &amp;&amp; y。)

现在,您希望 (y &amp;&amp; y)x 之前得到评估,但 Scala 总是从左到右评估(参见 language spec 的第 6.6 节)。而且,正如其他人所提到的,|| 是一个短路运算符,因此如果第一个操作数返回 true,则甚至不会计算第二个操作数。

另一种理解方式是调用两个方法,其中两个方法的第二个操作数都是按名称传递:

or (x, and(y, y))

def or(a: Boolean, b: => Boolean): Boolean = if (a) true else b
def and(a: Boolean, b: => Boolean): Boolean = if (!a) false else b

在从左到右的评估模型下,x 总是先被评估,然后可能y 被评估两次。

如果您还没有这样做,您可以在 Coursera 上关注 Martin Odersky 的函数式编程课程,他在第 1 课或第 2 课中谈到了这个主题。

你的第二个例子相当于

add(x, mult(y, y))

def add(a: Int, b: Int) = a + b
def mult(a: Int, b: Int) = a * b

x 总是首先被评估,然后y,两次。

【讨论】:

  • 这里的关键误解是 OP 假设 运算符优先级 对应于 求值顺序,但事实并非如此。
【解决方案2】:

它打印x,因为x() 调用返回true,并且在|| 逻辑运算符的情况下,如果左侧部分返回true,则不计算右侧部分。计算它使用| 然后,即使左边部分是true 右边部分也会被评估

更新

使用布尔值的示例不好,因为如果使用布尔值,则使用所谓的“短路”评估,如果左侧部分是 true,则 scalac 甚至不会查看 or 表达式的第二部分。把这个操作想象成:

def || (a: => Boolean) = ???

【讨论】:

  • 我知道,但没有解释。对我来说,它不应该在解决 y 之前查看 x
  • @Graduate 解释说,这通常不是一个很好的例子,因为布尔运算符在 scalac 中使用短路评估。如果左边是真的,Scala 就不会看右边的部分
猜你喜欢
  • 2011-06-21
  • 2020-03-05
  • 1970-01-01
  • 2011-01-22
  • 2021-03-29
  • 2013-07-31
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
相关资源
最近更新 更多