スカラーの継承でコンストラクタが呼び出される順序について、誰かが私に詳しく説明できますか?私が持っていると言う:スカラ:継承のコンストラクタ命令
abstract class A {
private var data: T = compute()
protected def compute(): T
}
class ImpA extends A {
var a = 0
override def compute() {
a = 1
null.asInstanceOf[T] // doesn't matter
}
}
val inst = new ImpA
そして、それはそのinst.a == 0
表示されますので、私は何が起こることはImpA
のコンストラクタは、その後、呼び出されたときに、A
コンストラクタが実際にa = 1
を設定する必要がありcompute()
をトリガする、とも呼ばれていることであると思います。しかし、スカラはImpA
のコンストラクタに戻り、a = 0
をリセットします。それですか?
これを正しく回避するためのよく知られたパターンがありますか? (私は本当に簡単に対処できるこの問題を解決しようとしているわけではありませんが、アドバイスされたパターンがあれば私はそれらを知りたいと思っていますが、何が起こっているのかを深く理解したいと思っています。うまくいけば、変数a
を再初期化することがなぜそのような場合に興味があるのか知っていればいいのですが、論理が保持されていれば同じ変数に複数の参照を割り当てるようになるので... val
であれば、
ありがとうございます。
EDIT:あなただけImpA.a
を変更し、代わりにvar
の参照を使用する場合楽しいもある何か:
class ImpA extends A {
class B {
var b = 0
}
val b = new B
override def compute() {
b.b += 1
null.asInstanceOf[T] // doesn't matter
}
}
b
がまだインスタンス化されていないので、それはjava.lang.NullPointerException
をスローします。 NullPointerException
がスローされた理由、それはかなり素直に説明し、それが適切に理解することは少し難しいですけれども
abstract class A extends Object {
private[this] var data: Object = _;
<accessor> private def data(): Object = A.this.data;
<accessor> private def data_=(x$1: Object): Unit = A.this.data = x$1;
protected def compute(): Object;
def <init>(): test.A = {
A.super.<init>();
A.this.data = A.this.compute();
()
}
};
class ImpA extends test.A {
private[this] val b: test.ImpA$B = _;
<stable> <accessor> def b(): test.ImpA$B = ImpA.this.b;
override def compute(): Unit = {
ImpA.this.b().b_=(ImpA.this.b().b().+(1));
{
(null: Object);
()
}
};
override <bridge> <artifact> def compute(): Object = {
ImpA.this.compute();
scala.runtime.BoxedUnit.UNIT
};
def <init>(): test.ImpA = {
ImpA.super.<init>();
ImpA.this.b = new test.ImpA$B(ImpA.this);
()
}
};
class ImpA$B extends Object {
private[this] var b: Int = _;
<accessor> def b(): Int = ImpA$B.this.b;
<accessor> def b_=(x$1: Int): Unit = ImpA$B.this.b = x$1;
<synthetic> <paramaccessor> <artifact> protected val $outer: test.ImpA = _;
<synthetic> <stable> <artifact> def $outer(): test.ImpA = ImpA$B.this.$outer;
def <init>($outer: test.ImpA): test.ImpA$B = {
if ($outer.eq(null))
throw null
else
ImpA$B.this.$outer = $outer;
ImpA$B.super.<init>();
ImpA$B.this.b = 0;
()
}
}
:Yuval Itzchakov
ソリューションに続き、ここではそれがにコンパイルものです。
しかし、あなたは、この時間lazy val b = new B
を使用している場合、それは動作します:
class ImpA extends test.A {
@volatile private[this] var bitmap$0: Boolean = false;
private def b$lzycompute(): test.ImpA$B = {
{
ImpA.this.synchronized({
if (ImpA.this.bitmap$0.unary_!())
{
ImpA.this.b = new test.ImpA$B(ImpA.this);
ImpA.this.bitmap$0 = true;
()
};
scala.runtime.BoxedUnit.UNIT
});
()
};
ImpA.this.b
};
lazy private[this] var b: test.ImpA$B = _;
<stable> <accessor> lazy def b(): test.ImpA$B = if (ImpA.this.bitmap$0.unary_!())
ImpA.this.b$lzycompute()
else
ImpA.this.b;
override def compute(): Unit = {
ImpA.this.b().b_=(ImpA.this.b().b().+(1));
{
(null: Object);
()
}
};
override <bridge> <artifact> def compute(): Object = {
ImpA.this.compute();
scala.runtime.BoxedUnit.UNIT
};
def <init>(): test.ImpA = {
ImpA.super.<init>();
()
}
};
編集を参照してください。気にしないで、私は読むことがあまりにも愚かだ... '計算は、()'どこにも呼び出されません。あなたはそれを定義しました。 –
@StefanFischer 'compute'は' A'のコンストラクタで呼び出されます。 –