A defpuò essere implementato da a def, a val, a lazy valo 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 F1o F3.
Ok, e per confonderti e rispondere @ om-nom-nom, l'uso di vals 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 vals.
Modifica (gennaio 2016): è consentito sostituire una valdichiarazione astratta con lazy valun'implementazione, in modo da evitare anche l'errore di inizializzazione.