A defkann entweder durch a def, a val, a lazy valoder an implementiert werden object. Es ist also die abstrakteste Form, ein Mitglied zu definieren. Da Merkmale normalerweise abstrakte Schnittstellen sind, bedeutet die Aussage, dass Sie eine möchten val, wie die Implementierung funktionieren soll. Wenn Sie nach a fragen val, kann eine implementierende Klasse a nicht verwenden def.
A valwird nur benötigt, wenn Sie eine stabile Kennung benötigen, z. B. für einen pfadabhängigen Typ. Das brauchen Sie normalerweise nicht.
Vergleichen Sie:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) } // ok
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = { // ok
Thread.sleep(5000) // really heavy number crunching
42
}
}
Wenn du hättest
trait Foo { val bar: Int }
Sie würden nicht definieren können F1oder F3.
Ok, und um Sie zu verwirren und @ om-nom-nom zu beantworten - die Verwendung von Abstracts valkann zu Initialisierungsproblemen führen:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko // zero!!
Dies ist ein hässliches Problem, das meiner persönlichen Meinung nach in zukünftigen Scala-Versionen behoben werden sollte, indem es im Compiler behoben wird. Ja, derzeit ist dies auch ein Grund, warum man keine abstrakten vals verwenden sollte.
Bearbeiten (Januar 2016): Sie dürfen eine abstrakte valDeklaration mit einer lazy valImplementierung überschreiben , um auch den Initialisierungsfehler zu verhindern.