2013-04-02 41 views
7

Nếu tôi viết:Cách khởi tạo giá trị từ đặc điểm trong loại phụ?

trait T { 
    val t = 3 
    val u = 1::t::Nil 
} 

class U extends T { 
    override val t = 2 
} 

(new U).u 

nó sẽ hiển thị điều này.

List(1, 0) 

Làm thế nào tôi nên thay đổi mã trên để làm cho nó hiển thị như sau:

List(1, 2) 

ví dụ override val t đặt giá trị của t cho u trong đặc điểm T?

+1

bạn có thể xác định u là 'lazy val' –

Trả lời

12

Một cách để làm điều này là để trì hoãn đánh giá u bằng cách sử dụng def hoặc lazy val như sau:

trait T { 
    def t = 3 
    def u = 1::t::Nil 
} 

class U extends T { 
    override def t = 2 
} 

(new U).u 

hoặc

trait T { 
    val t = 3 
    lazy val u = 1::t::Nil 
} 

class U extends T { 
    override val t = 2 
} 

(new U).u 

Sự khác biệt như sau:

  • val làm cho một biểu thức đánh giá trong quá trình khởi tạo
  • def làm cho một biểu thức đánh giá mỗi lần u được sử dụng
  • lazy val làm cho nó đánh giá về việc sử dụng đầu tiên u và lưu trữ kết quả
10

Hãy thử sử dụng một initializer sớm:

scala> trait T { 
    | val t = 3 
    | val u = 1::t::Nil 
    | } 
defined trait T 

scala> class U extends { 
    | override val t = 2; 
    | } with T 
defined class U 

scala> (new U).u 
res1: List[Int] = List(1, 2) 

Xem ví dụ here để biết thêm thông tin về khởi tạo sớm.

+0

Mặc dù chính xác, vì lý do dễ đọc, tôi thích sử dụng phương pháp bộ nhớ cache với các vals lười. Nếu tôi cần thêm mã vào lớp U của mình, tôi không thể đặt mã vào dấu ngoặc, tôi cần tạo một nhóm khác, như lớp U mở rộng {ghi đè val t = 2} bằng T {... mã của tôi ở đây ... } –

+0

Vấn đề với cách tiếp cận này là mọi truy cập được đồng bộ hóa để đảm bảo rằng 'lazy val' đã sẵn sàng. Nó làm chậm ứng dụng và không nên sử dụng một cách mù quáng trên các đường dẫn quan trọng. –

4

Tất cả kiểu khai báo scala chỉ là ảo ảnh. Scala được xây dựng dựa trên jvm và hoạt động như java.

Evetything là một lớp và phải độc lập với cách sử dụng của nó (java không phải là C++ và hỗ trợ xây dựng gia tăng với ưu và nhược điểm của nó). Mỗi đặc điểm có mã khởi tạo riêng của nó và lớp đa đặc điểm chạy từng mã khởi tạo tương ứng. Nếu bạn sử dụng một số AnyRef được khai báo chỉ trong một lớp con hơn giá trị của nó sẽ được đặt cho null trong khi khởi tạo.

Tôi tự bảo vệ mình bằng quy tắc quy tắc cụ thể: mọi val phải là cuối cùng hoặc lười (why using plain val in non-final classes). Vì vậy, tôi không quan tâm đến thứ tự khởi tạo và có thể giả vờ thêm rằng tôi đang sử dụng ngôn ngữ khai báo.

Ngoài ra tôi đang sử dụng tùy chọn -Xcheckinit: Thêm kiểm tra thời gian chạy vào trường truy cập.

Các vấn đề liên quan