A def
kann entweder durch a def
, a val
, a lazy val
oder 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 val
wird 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 F1
oder F3
.
Ok, und um Sie zu verwirren und @ om-nom-nom zu beantworten - die Verwendung von Abstracts val
kann 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 val
s verwenden sollte.
Bearbeiten (Januar 2016): Sie dürfen eine abstrakte val
Deklaration mit einer lazy val
Implementierung überschreiben , um auch den Initialisierungsfehler zu verhindern.