A defcó thể được thực hiện bởi a def, a val, a lazy valhoặc an object. Vì vậy, nó là hình thức trừu tượng nhất để xác định một thành viên. Vì các đặc điểm thường là các giao diện trừu tượng, nói rằng bạn muốn a vallà nói cách triển khai nên thực hiện. Nếu bạn yêu cầu a val, một lớp thực thi không thể sử dụng a def.
A valchỉ cần thiết nếu bạn cần một số nhận dạng ổn định, ví dụ: đối với kiểu phụ thuộc vào đường dẫn. Đó là thứ bạn thường không cần.
So sánh:
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
}
}
Nếu bạn có
trait Foo { val bar: Int }
bạn sẽ không thể xác định F1hoặc F3.
Ok, và làm bạn bối rối và hãy trả lời @ om-nom-nom — việc sử dụng trừu tượng valcó thể gây ra sự cố khởi tạo:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko
Đây là một vấn đề xấu mà theo ý kiến cá nhân của tôi sẽ biến mất trong các phiên bản Scala trong tương lai bằng cách sửa nó trong trình biên dịch, nhưng có, hiện tại đây cũng là lý do tại sao người ta không nên sử dụng trừu tượng vals.
Chỉnh sửa (tháng 1 năm 2016): Bạn được phép ghi đè một valkhai báo trừu tượng bằng một lazy valtriển khai, vì vậy điều đó cũng sẽ ngăn chặn lỗi khởi tạo.