A def
dapat diimplementasikan oleh a def
, a val
, a lazy val
atau an object
. Jadi ini adalah bentuk paling abstrak untuk mendefinisikan anggota. Karena sifat biasanya antarmuka abstrak, mengatakan Anda menginginkan a val
berarti mengatakan bagaimana implementasi harus dilakukan. Jika Anda meminta a val
, kelas pelaksana tidak dapat menggunakan def
.
A val
diperlukan hanya jika Anda membutuhkan pengenal yang stabil, misalnya untuk tipe yang bergantung pada jalur. Itu adalah sesuatu yang biasanya tidak Anda butuhkan.
Membandingkan:
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
}
}
Jika Anda punya
trait Foo { val bar: Int }
Anda tidak akan bisa mendefinisikan F1
atau F3
.
Oke, dan untuk membingungkan Anda dan jawab @ om-nom-nom — menggunakan abstrak val
dapat menyebabkan masalah inisialisasi:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko
Ini adalah masalah buruk yang menurut pendapat pribadi saya harus hilang di versi Scala mendatang dengan memperbaikinya di kompiler, tapi ya, saat ini ini juga merupakan alasan mengapa seseorang tidak boleh menggunakan abstrak val
.
Sunting (Jan 2016): Anda diizinkan untuk mengganti val
deklarasi abstrak dengan lazy val
implementasi, sehingga akan mencegah kegagalan inisialisasi.