A def
può essere implementato da a def
, a val
, a lazy val
o an object
. Quindi è la forma più astratta per definire un membro. Poiché i tratti sono solitamente interfacce astratte, dire che si desidera una val
è dire come dovrebbe fare l'implementazione. Se chiedi a val
, una classe di implementazione non può utilizzare a def
.
A val
è necessario solo se è necessario un identificatore stabile, ad esempio per un tipo dipendente dal percorso. È qualcosa di cui di solito non hai bisogno.
Confrontare:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) }
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = {
Thread.sleep(5000)
42
}
}
Se tu avessi
trait Foo { val bar: Int }
non saresti in grado di definire F1
o F3
.
Ok, e per confonderti e rispondere @ om-nom-nom, l'uso di val
s astratte può causare problemi di inizializzazione:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko
Questo è un brutto problema che a mio parere personale dovrebbe scomparire nelle future versioni di Scala riparandolo nel compilatore, ma sì, attualmente questo è anche un motivo per cui non si dovrebbero usare abstract val
s.
Modifica (gennaio 2016): è consentito sostituire una val
dichiarazione astratta con lazy val
un'implementazione, in modo da evitare anche l'errore di inizializzazione.