private [this] on mutable constructor参数导致意外行为

时间:2016-05-16 14:19:57

标签: scala

当我运行下面的代码时,

class A(private[this] var i: Int) {
  println("i = " + i)
  i -= 1
  println("After decrement, i = " + i)

  override def toString = i.toString
}
object A extends App {
  val a = new A(1)
  println("a = " + a)
}

我明白了:

i = 1
After decrement, i = 0
a = 1

如果我将private[this]替换为private,我会得到预期的行为,即最后一行输出为a = 0。我使用的是IntelliJ 2016.1.2,Scala插件版本3.0.6和scala-sdk-2.11.8。

2 个答案:

答案 0 :(得分:8)

这是一个错误。请参阅SI-6880

构造函数var上的

private[this]会导致它错误地影响自身,并且您获得原始值而不是所需的访问器。

答案 1 :(得分:6)

是的,it's a bugSI-6165SI-6880)。

让我们进一步探讨。这是两种情况的反编译代码:

private[this]

class A extends Object {
  <paramaccessor> private[this] var i: Int = _;
  override def toString(): String = scala.Int.box(A.this.i).toString();
  def <init>(i: Int): com.yuval.A = {
    A.this.i = i;
    A.super.<init>();
    scala.this.Predef.println("i = ".+(scala.Int.box(i)));
    i = i.-(1);
    scala.this.Predef.println("After decrement, i = ".+(scala.Int.box(i)));
    ()
  }
};

在这里,我们看到为对象创建了var i,并在代码中直接访问 。我们看到i已分配给A.this.i,这是对该字段的直接分配。稍后,将变异值分配给方法参数i,而不是A.this.i,类A的字段。实际值{{1}被遮蔽了。

相反,当ii时:

private

在这里,我们看到class A extends Object { <paramaccessor> private[this] var i: Int = _; <accessor> <paramaccessor> private def i(): Int = A.this.i; <accessor> <paramaccessor> private def i_=(x$1: Int): Unit = A.this.i = x$1; override def toString(): String = scala.Int.box(A.this.i()).toString(); def <init>(i: Int): com.yuval.A = { A.this.i = i; A.super.<init>(); scala.this.Predef.println("i = ".+(scala.Int.box(A.this.i()))); A.this.i_=(A.this.i().-(1)); scala.this.Predef.println("After decrement, i = ".+(scala.Int.box(A.this.i()))); () } }; 有一个getter和setter方法,与i不同。我们还看到减少是在private[this]上完成的,A.this.i_是字段成员A.this.i的设置者。