2015-07-14 13 views
13

Tại sao không thể ghi đè biến có thể thay đổi trong scala?Tại sao không thể ghi đè biến có thể biến đổi trong scala?

class Abs(var name: String){ 
} 

class AbsImpl(override var name: String) extends Abs(name){ 
} 

Trên đang cung cấp cho lỗi sau thời gian biên dịch: -

variable name cannot override a mutable variable

Nếu tên được khai báo val, sau đó mã ở trên hoạt động tốt.

+0

Tại sao một người nào đó muốn 'ghi đè' một' var'? Ý nghĩa của việc ghi đè một var là gì? –

+0

Bởi vì việc ghi đè nó không thực sự có ý nghĩa nhiều. Nó có thể thay đổi, bạn chỉ có thể thay đổi nó.Điều gì làm trọng số thậm chí có nghĩa là gì? http://stackoverflow.com/questions/16413986/how-to-override-a-mutable-variable-in-trait-in-scala – Falmarri

+0

@Sarvesh: Cảm ơn phản hồi nhanh của bạn. Tôi chỉ cố gắng để hiểu, tại sao nó được phép cho val? – mogli

Trả lời

4

Nếu bạn có thể ghi đè một var bằng var, thì thành viên ghi đè có thể có loại hẹp hơn. (Đó là cách ghi đè được xác định.)

Sau đó, bạn có thể chỉ định giá trị của loại rộng hơn và sau đó đọc nó mong đợi loại hẹp hơn và không thành công.

Minh họa setter tham gia:

scala> class A ; class B extends A 
defined class A 
defined class B 

scala> abstract class C { var x: A } ; class D extends C { var x: B = _ } 
<console>:13: error: class D needs to be abstract, since variable x in class C of type A is not defined 
(Note that an abstract var requires a setter in addition to the getter) 
     abstract class C { var x: A } ; class D extends C { var x: B = _ } 
              ^

scala> abstract class C { var x: A } 
defined class C 

scala> class D extends C { var x: B = _ ; def x_=(a: A) = ??? } 
defined class D 
+0

Khi bạn ghi đè, không phải là bạn có thể có "loại hẹp hơn". Trên thực tế, nó ghi đè lên hai phương thức, getter và setter. Điều đầu tiên là biến thể trong kiểu var, thứ hai là contravariant trong kiểu var, vì vậy ngay cả khi bạn đã ghi đè, kiểu sẽ là bất biến. –

+0

@ MikaëlMayer Đó là một cách khác để nói những gì tôi đã chứng minh, ngoại trừ việc định nghĩa của các thành viên ghi đè bắt đầu với sự phù hợp và không phải với desugaring. http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#overriding –

+0

Việc giải thích các vars như getter và setter là chỉ có một được hỗ trợ bởi spec . Mối quan hệ phù hợp không xử lý các biến, chỉ có các phương thức và các biến, nhưng các biến được định nghĩa là "tương đương" với một trình lấy và lấy ra. http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#variable-declarations-and-definitions. Tôi sẽ nói nó nên được cho phép. Thay vào đó nó không được phép ngay cả khi người ta cố gắng ghi đè thông qua một getter và setter. Bí ẩn tiếp tục. –

0

này xảy ra khi var bạn đang cố gắng để ghi đè lên đã có một bài tập. Tôi không chắc chắn lý do tại sao điều này bị cấm, nhưng cũng có ý nghĩa rất ít.

Xem thêm this question.

Xác định name như trừu tượng thay vì

trait Abs { 
    var name: String 
} 

class AbsImpl(name0: String) extends Abs { 
    var name = name0 
} 

hoặc

trait Abs { 
    var name: String 
} 

class AbsImpl(private var name0: String) extends Abs { 
    def name = { 
    println("getter") 
    name0 
    } 

    def name_=(value: String) = { 
    println("setter") 
    name0 = value 
    } 
} 
1

Tôi tin rằng mục đích đơn giản là để thiết lập giá trị của di truyền var name. Điều này có thể đạt được theo cách này (không override var):

class Abs(var name: String){ 
} 

class AbsImpl(name: String) extends Abs(name){ 
} 

Sự mơ hồ phát sinh từ các địa phương var name: String trong AbsImpl được đặt tên sau khi thừa hưởng var name: String từ Abs. Một mã tương tự, ít cú pháp mơ hồ nhưng cũng ít thanh lịch sẽ là:

class Abs(var name: String){ 
} 

class AbsImpl(name_value: String) extends Abs(name_value){ 
} 
2

Câu trả lời ngắn gọn: bạn cần phải vượt qua -Yoverride-vars để trình biên dịch Scala.

Theo thông số kỹ thuật, var vừa là bộ nạp tiền vừa là người đặt cược và quy tắc ghi đè thông thường sẽ áp dụng cho các phương pháp này. Tuy nhiên, điều này đã chứng minh có một số hậu quả không mong muốn w.r.t. vào từ khóa final và nội tuyến. Các mã trong trình biên dịch đề cập đến một số giải thích đặc tả sẽ là cần thiết:

// TODO: this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here. 
if (!settings.overrideVars) 
    overrideError("cannot override a mutable variable") 

Một vé liên quan: SI-3770

+0

Tôi không chắc chắn 'class C {def c = 42; def c _ = (x: Int): Đơn vị =()}; (new C): {var c: Int} 'sẽ hoạt động. Ai đó gần đây đã ngạc nhiên bởi 'class C {val c = 42}; (mới C) .c _'. Có lẽ spec nên rõ ràng thống nhất chúng. Tôi thấy tôi không thể 'class C {var c: Any = _}; lớp D mở rộng C {override var c: Int = 42; def c _ = (x: Any) = c _ = (x.toString.toInt)} 'ít nhất là không nghỉ trưa của tôi. –

0

Khi bạn muốn trọng một var tương đương của nó để cố gắng để ghi đè lên một lĩnh vực trong java mà là không thể .

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