0

在“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

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

4

2 回答 2

3

原始版本:

x || y && y

应用优先级:

x || (y && y)

(注意,如果优先级被颠倒,它将是(x || y) && y。)

现在,您希望(y && y)在 before 得到评估x,但 Scala 总是从左到右评估(参见语言规范的 §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两次。

如果您还没有这样做,您可以关注 Martin Odersky 在Coursera上的函数式编程课程,他在第 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,两次。

于 2013-09-26T09:25:06.870 回答
2

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

更新

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

def || (a: => Boolean) = ???
于 2013-09-26T08:11:53.377 回答