Scala中的方法执行难题

时间:2011-11-25 08:29:41

标签: java c scala operator-precedence

首先我宣布一个班级:

class Op(var x : Int) {
  def +++(op: Op) = {
    println(this.x + " +++ " + op.x)
    this.x += op.x
    this
  } 
  def ***(op: Op) = {
    println(this.x + " *** " + op.x)
    this.x *= op.x
    this
  }
}

现在我在REPL中执行表达式:

op1 +++ op2 +++ op3 *** op4

并输出

enter image description here

但为什么方法***不是先行? ***的优先级不高于+++吗? Java和C怎么样?它和Scala一样吗?

2 个答案:

答案 0 :(得分:13)

op1 +++ op2 +++ op3 *** op4

相当于

((op1 +++ op2) +++ (op3 *** op4))

因为方法调用是左关联的。因此,首先评估(op1 +++ op2),因为它是第二个+++的第一个操作数。然后评估第二个操作数(op3 *** op4)。最后,评估最外层的运算符。

对于C或Java中的op1 + op2 + op3 * op4也是如此。

答案 1 :(得分:5)

简单规则

有两个规则决定op1 +++ op2 +++ op3 *** op4表达式评估的顺序:

首先,因为以*开头的运算符优先于以+开头的运算符,所以表达式转换为:

op1 +++ op2 +++ (op3 *** op4)

其次,因为有多个相同优先级的运算符并排出现(op1 +++ op2 +++ ...),所以它们从左到右分组:

(op1 +++ op2) +++ (op3 *** op4)

实施例

考虑以下表达式:

op1 +++ op2 +++ op3 +++ op4 *** op5

遵循相同的两个简单规则,它将被评估为:

((op1 +++ op2) +++ op3) +++ (op4 *** op5)

另一个例子

或者,我们将相同的两个规则应用于op1 +++ op2 +++ op3 +++ op4 *** op5 *** op6

以*开头的运算符优先于以+:

开头的运算符
op1 +++ op2 +++ op3 +++ (op4 *** op5 *** op6)

然后从左到右分组具有相同优先级的运算符:

((op1 +++ op2) +++ op3) +++ ((op4 *** op5) *** op6)

可变对象:谨慎之言

如果+++***方法没有任何副作用,则分组具有完美的数学意义。考虑:

op1 +++ op2 +++ op1 *** op2

直观地,表达式应该返回一个持有5的对象。但是,由于+++***方法在原始代码示例中产生的不幸副作用(两者都修改了存储在对象中的值)表达式将导致一个对象保持12而不是预期的5.

这就是为什么在构造这样的表达式时最好完全依赖不可变对象:

case class Op ( x: Int) {
  def +++(that: Op) = {
    println(this.x + " +++ " + that.x)
    Op(this.x+that.x)
  } 
  def ***(that: Op) = {
    println(this.x + " *** " + that.x)
    Op(this.x * that.x)
  }  
}

Op(1) +++ Op(2) +++ Op(1) *** Op(2)表达式将按预期生成Op(5)