A defможе бути реалізований будь-яким з a def, a val, a lazy valабо an object. Отже, це найбільш абстрактна форма визначення члена. Оскільки риси, як правило, є абстрактними інтерфейсами, сказати, що ви хочете, valце сказати, як має бути реалізація. Якщо ви просите a val, клас, що реалізує, не може використовувати adef .
A valпотрібен лише в тому випадку, якщо вам потрібен стабільний ідентифікатор, наприклад для типу, що залежить від шляху. Це те, що вам зазвичай не потрібно.
Порівняйте:
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
}
}
Якби у вас було
trait Foo { val bar: Int }
ви не змогли б визначити F1або F3.
Гаразд, і щоб ви заплутали вас і відповіли @ om-nom-nom - використання абстрактних vals може спричинити проблеми з ініціалізацією:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko
Це потворна проблема, яка, на мою особисту думку, повинна зникнути в майбутніх версіях Scala, виправивши її в компіляторі, але так, наразі це також причина, чому не слід використовувати абстрактні vals.
Редагувати (січень 2016 р.): Вам дозволено замінити абстрактну valдекларацію lazy valреалізацією, щоб це також запобігло помилці ініціалізації.