当我运行下面的代码时,
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。
答案 0 :(得分:8)
这是一个错误。请参阅SI-6880。
构造函数var上的 private[this]
会导致它错误地影响自身,并且您获得原始值而不是所需的访问器。
答案 1 :(得分:6)
是的,it's a bug(SI-6165,SI-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}被遮蔽了。
相反,当i
为i
时:
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
的设置者。