A def
có thể được thực hiện bởi a def
, a val
, a lazy val
hoặ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 val
là 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 val
chỉ 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 F1
hoặ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 val
có 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 val
s.
Chỉnh sửa (tháng 1 năm 2016): Bạn được phép ghi đè một val
khai báo trừu tượng bằng một lazy val
triển khai, vì vậy điều đó cũng sẽ ngăn chặn lỗi khởi tạo.