A def
peut être implémenté soit par a def
, a val
, a lazy val
ou an object
. C'est donc la forme la plus abstraite de définition d'un membre. Puisque les traits sont généralement des interfaces abstraites, dire que vous voulez un, val
c'est dire comment l'implémentation doit fonctionner. Si vous demandez a val
, une classe d'implémentation ne peut pas utiliser a def
.
A val
n'est nécessaire que si vous avez besoin d'un identifiant stable, par exemple pour un type dépendant du chemin. C'est quelque chose dont vous n'avez généralement pas besoin.
Comparer:
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
}
}
Si tu avais
trait Foo { val bar: Int }
vous ne seriez pas en mesure de définir F1
ou F3
.
Ok, et pour vous embrouiller et répondre @ om-nom-nom - l'utilisation de val
s abstraits peut causer des problèmes d'initialisation:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko
C'est un problème horrible qui, à mon avis personnel, devrait disparaître dans les futures versions de Scala en le corrigeant dans le compilateur, mais oui, actuellement c'est aussi une raison pour laquelle on ne devrait pas utiliser de résumé val
.
Edit (Jan 2016): Vous êtes autorisé à remplacer une val
déclaration abstraite avec une lazy val
implémentation, ce qui empêcherait également l'échec de l'initialisation.