またはval
、scalaオブジェクトのsはデフォルトで怠惰ですか?
val
とにかく、を使用して怠惰なオブジェクトでを宣言する必要がある場合、次のlazy
ようなことを行うことは可能ですか?
lazy object SomeObject
または(C ++で行うように)
object A {
lazy:
val a
val b
...
}
怠惰になりたいので、すべてval
のラベルを変更する必要はありませんlazy val
またはval
、scalaオブジェクトのsはデフォルトで怠惰ですか?
val
とにかく、を使用して怠惰なオブジェクトでを宣言する必要がある場合、次のlazy
ようなことを行うことは可能ですか?
lazy object SomeObject
または(C ++で行うように)
object A {
lazy:
val a
val b
...
}
怠惰になりたいので、すべてval
のラベルを変更する必要はありませんlazy val
最初の質問に答えるには(「val
デフォルトでscalaオブジェクトのsは怠惰ですか?」):いいえ、正確ではありませんが、オブジェクト自体は一種の怠惰であり、十分に怠惰である可能性があります。Scala言語仕様の5.4(「オブジェクト定義」)から:
オブジェクト定義によって定義された値は遅延してインスタンス化されることに注意してください。コンストラクターは、
new m$cls
オブジェクト定義の時点では評価されませんが、代わりm
に、プログラムの実行中に最初に逆参照されるときに評価されます(これはまったく行われない可能性があります)。
したがって、たとえば、次の3つのオブジェクトがある場合:
object X {
val answer = { println("Here's X's answer!"); 42 }
}
object Y {
lazy val answer = { println("Here's Y's answer!"); 1 }
}
object Z extends App {
println("Here we go.")
println(X)
println(Y)
println(X.answer)
println(Y.answer)
}
次に、を実行するZ
と、次のように表示されます。
Here we go.
Here's X's answer!
X$@38d24866
Y$@f1aa6ce
42
Here's Y's answer!
1
したがって、val
inX
は怠惰ではありませんが、初めて使用するまで評価されませんX
。
簡単な答えは次のとおりです。いいえ、それは不可能です(マクロで非常識なクランチを行っていない場合を除く)。
まず第一に、オブジェクトはすでに怠惰に初期化されています:
object Y {
println("aqui")
val a = 0
}
Y.a // runs body of Y
次に、複数のsが一度val
に遅延初期化されることに満足している場合は、タプルからのパターン抽出を使用できます。
object X {
val a = 0
lazy val (b, c) = {
println("aqui")
(1, "hallo")
}
}
X.a // runs body of X, initialises strict vals
X.b // initialises both b and c
X.c
狂気(@ om-nom-nom)と言えば、怠惰なラッパーを作成するようにAutoproxyプラグインを適応させることが可能かもしれません。それは...面白いでしょう。\
一般に、Scalaコンパイラプラグインを使用するとこれを実行できます。マーカー特性または注釈を介して遅延オブジェクトにタグを付けてから、コンパイラプラグインに書き換えを行わせることができます。コンパイラプラグインを作成するのは簡単なことではありませんが、それでも楽しい場合があります。