A defmożna zaimplementować za pomocą a def, a val, a lazy vallub an object. Jest to więc najbardziej abstrakcyjna forma definiowania członka. Ponieważ cechy są zwykle abstrakcyjnymi interfejsami, stwierdzenie, że chcesz, valto powiedzenie, jak powinna działać implementacja. Jeśli poprosisz o a val, klasa implementująca nie może użyć def.
A valjest potrzebne tylko wtedy, gdy potrzebujesz stabilnego identyfikatora, np. Dla typu zależnego od ścieżki. To jest coś, czego zwykle nie potrzebujesz.
Porównać:
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
}
}
Gdybyś miał
trait Foo { val bar: Int }
nie byłbyś w stanie zdefiniować F1lub F3.
OK, i żeby zmylić Cię i odpowiedzieć @ om-nom-nom - użycie abstrakcyjnych vals może powodować problemy z inicjalizacją:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko
Jest to brzydki problem, który moim zdaniem powinien zniknąć w przyszłych wersjach Scali poprzez naprawienie go w kompilatorze, ale tak, obecnie jest to również powód, dla którego nie należy używać abstrakcyjnych vals.
Edycja (styczeń 2016 r.): Możesz zastąpić abstrakcyjną valdeklarację lazy valimplementacją, aby również zapobiec niepowodzeniu inicjalizacji.