2013-01-11 29 views
5

Tôi đã mã:Lỗi với hiệp biến định nghĩa và các loại contravariant

class A { 
    override def toString = "object class A" 
} 

class B extends A { 
    override def toString = "object class B" 
} 

class Cell[+T](init: T) { 
    private[this] var current: T = init 
    def get: T = current 
    def set(x: T) { current = x } 
} 

val cB = new Cell[B](new B) 
println(cB.get) 
val cA: Cell[A] = cB 
println(cA.get) 

nhưng tôi có lỗi trong dòng: def set(x: T) { current = x }

error: covariant type T occurs in contravariant position in type T of value x def set(x: T) { current = x }

Giải thích, xin vui lòng

+1

Ngoài những câu trả lời sâu sắc, tại sao bạn cần tham chiếu tin rõ ràng và getter/setter? Scala làm điều này cho bạn: 'lớp tế bào [+ T] (val t: T) {...}' –

Trả lời

5

vị trí contravariant cho một loại là (trong số những người khác) bất kỳ vị trí nào cho phép bạn chuyển một thể hiện của loại đó sang một phương thức. Vì vậy, tất cả các kiểu tham số phương thức đều nằm trong các vị trí contravariant. Vì bạn khai báo T là covariant (+T), trình biên dịch sẽ không cho phép điều này. lựa chọn duy nhất của bạn là:

  • làm T bất biến
  • sửa đổi phương thức thiết lập như vậy mà nó trả về một thể hiện mới của CellCell do đó trở nên bất biến.
  • loại bỏ các phương pháp thiết lập, cũng làm cho Cell bất biến

Nếu trình biên dịch cho phép bạn để có một phương pháp thiết lập khi bạn thực hiện nó, điều đó sẽ làm cho hệ thống loại không an toàn, vì nó sẽ cho phép bạn viết:

val cs:Cell[String] = new Cell("") 
val ca:Cell[Any] = cs 
ca.set(5) 
val s:String = cs.get //boom 
+0

Nên là 'ca.set (5)' thay vì 'cs.set (5)' –

+0

cảm ơn, thay đổi nó –

4

Câu trả lời ngắn gọn là bạn không thể có vùng chứa có thể thay đổi là biến thể. Giả sử biên soạn này, sau đó trong ví dụ của bạn, hai dòng cuối cùng có thể đọc:

val cA: Call[A] = cB 
cA.set(new A) 

Dòng đầu tiên sẽ được phép, bởi vì một Cell[B] một Cell[A] do việc sử dụng các +T. Và sau đó dòng thứ hai được cho phép quá - bởi vì tất nhiên bạn có thể thiết lập một Cell[A] để giữ một A.

Nhưng bây giờ, cB.get trả về phiên bản A, không phải là B! Điều này không có ý nghĩa gì cả, và không có cách nào để giải quyết mâu thuẫn này trong khi vẫn cho phép hiệp phương sai trong tham số kiểu của ô.


Đối với một câu trả lời dài hơn, chính thức/toàn diện hơn, xem câu hỏi này: Scala covariance/contravariance

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