2009-11-17 2 views
7

Tôi muốn làm một cái gì đó như thế này:Làm thế nào để phân lớp một đối tượng với một var trong constructor chính của nó

class A (var updateCount: Int) { 
} 

class B (val name: String, var updateCount: Int) extends A(updateCount) { 
    def inc(): Unit = { 
    updateCount = updateCount + 1 
    } 
} 

var b = new B("a", 10) 
println(b.name) 
println(b.updateCount) 

b.updateCount = 9999 
b.inc 
println(b.updateCount) 

nhưng trình biên dịch không thích nó.

(fragment of extend.scala):5: error: error overriding variable updateCount in class A of type Int; 
variable updateCount needs `override' modifier 
class B (val name: String, var updateCount: Int) extends A(updateCount) { 

Thêm ghi đè khi cập nhậtCount cũng không hoạt động. Cách sạch sẽ để làm điều này là gì?

+0

Một vài người đã chỉ ra rằng tôi nên xóa var khỏi bản cập nhậtCount in B. Điều này không hiệu quả. Nếu bạn thử, bạn sẽ nhận được (đoạn mở rộng.scala): 7: lỗi: chuyển nhượng lại cho val updateCount = updateCount + 1 sắp ra khỏi phương pháp inc. – Trenton

Trả lời

7

Bạn không cần phải khai báo var trong chữ ký constructor lớp con:

class B (val name: String, /* note no var */ updateCount: Int) extends A(updateCount) { 
    //... 
} 

này cũng mở rộng đến các lớp học với val s trong nhà thầu của họ cũng:

scala> class C(val i: Int) 
defined class C 

scala> class D(j: Int) extends C(j) 
defined class D 
+0

Điều này không hoạt động. Nếu tôi sử dụng ví dụ chính xác mà tôi đã cung cấp, hãy xóa var khỏi updateCount, tôi nhận được (đoạn extend.scala): 7: lỗi: chỉ định lại val updateCount = updateCount + 1 sắp ra khỏi phương pháp inc. – Trenton

+0

Bạn chỉ cần đổi tên các tham số trong lớp B: sử dụng 'updateCountIn' trong chữ ký hàm tạo và gọi tới hàm tạo của lớp A; bạn vẫn có thể truy cập 'updateCount' trong hàm tạo/thân của lớp B. – bbarker

4

Bạn cần tránh có số nhận dạng được khai báo cho số B che dấu số nhận dạng được khai báo cho A. Cách dễ nhất để làm điều đó là chọn một tên khác. Tuy nhiên, nếu bạn thực sự, thực sự không muốn làm điều đó, đây là một sự thay thế:

class B (val name: String, updateCount: Int) extends A(updateCount) { 
    self: A => 
    def inc(): Unit = { 
    self.updateCount = self.updateCount + 1 
    } 
} 

Và, bằng cách này, thả var từ khai B.

+1

Chà, đó là một công việc khá xung quanh.Điều này có vẻ như một giới hạn kỳ lạ của ngôn ngữ. Nếu tôi có một đồ thị thừa kế 5 sâu, tôi có cần phải tiếp tục đưa ra những cái tên "giả" cho những người này không? updateCountDontUse1, và trong lớp con updateCountDontUse2, vv? Nó không chỉ là tên ... nó cũng là tàu tuần dương. Đó là một lĩnh vực phụ đang ngồi trong lớp của tôi, cầu xin ai đó sử dụng nó và nhận được kết quả xấu. – Trenton

+2

Đó là điều ... các tham số cho lớp không thực sự là các trường, trừ khi được đặt trước với 'val' hoặc' var'. Nếu bạn không sử dụng chúng ở bất cứ nơi nào nhưng hàm tạo, chúng sẽ không được lưu trữ như các trường trong lớp. –

2

Khi bạn sử dụng từ khóa var trong thông số, điều này làm cho giá trị được chuyển thành một mới var trong lớp. Khi bạn không làm điều đó, nó làm cho nó một tham số constructor (chỉ), và bạn sử dụng giá trị của nó cho var bằng cách chuyển nó tới hàm tạo. Vì vậy, ví dụ mà mọi người đã đưa ra

class B(val name:String, updateCount:Int) extends A(updateCount) 

là chính xác. Tuy nhiên, scala làm cho các tham số khởi tạo có sẵn trực tiếp cho các phương thức trong lớp (tôi không chắc chắn lý do), vì vậy nếu bạn sử dụng cùng tên, bạn sẽ thấy mã của bạn không biên dịch được với lỗi reassignment to val khi bạn thử để gán lại "var". Ví dụ trong đoạn mã sau, tham số hàm tạo bất biến đổ bóng var kế thừa và do đó bạn không thể gán cho tham số.

class B (val name: String, updateCount: Int) extends A(updateCount) { 
    def inc(): Unit = { 
    updateCount = updateCount + 1 
    } 
} 
+0

lớp B (val name: String, updateCount: Int) mở rộng A (updateCount) sẽ không biên dịch cho tôi. Tôi nhận được (đoạn extend.scala): 7: lỗi: chuyển nhượng lại cho val updateCount = updateCount + 1 – Trenton

+0

Phiên bản đầu tiên biên dịch. Phiên bản thứ hai cố ý không, và chứng minh vấn đề bằng cách sử dụng cùng tên cho tham số var và constructor. –

0

Như những người khác đề cập đến, thông số hàm tạo của bạn trong B đang che khuất phiên bản của lớp cha. Đây là mã hoạt động và không yêu cầu tự nhập:

class A (var updateCount: Int) { 
} 

class B (val name: String, uc: Int) extends A(uc) { 
    def inc(): Unit = { 
    updateCount = updateCount + 1 
    } 
}