2012-03-08 48 views
31

我試圖使用協變類型參數特徵的內部構造的情況下,類像這樣:爲什麼參數處於逆變位置?

trait MyTrait[+T] { 
    private case class MyClass(c: T) 
} 

編譯器說:

error: covariant type T occurs in contravariant position in type T of value c 

然後我試過以下,但它也沒「T工作:

trait MyTrait[+T] { 
    private case class MyClass[U <: T](c: U) 
} 

錯誤這段時間是:

error: covariant type T occurs in contravariant position in type >: Nothing <: T of type U 

有人能解釋爲什麼T是協變位置,在這裏,並提出一個解決這個問題? Thx!

+0

你能解釋一下你真正想做什麼嗎?你爲什麼要T協變而不是不變? – 2012-03-08 15:40:42

回答

61

這是面向對象編程因爲它值得不會得到儘可能多的關注的一個基本特徵。

假設你有一個集合C[+T]+T意思是說,如果U <: T,那麼C[U] <: C[T]。很公平。但是成爲一個子類是什麼意思?這意味着每個方法應該工作對原始類的工作。所以,假設你有一個方法m(t: T)。這說你可以採取任何t並做一些事情。但C[U]只能做U,這可能不是全部T!因此,您立即反駁了您的說法,即C[U]C[T]的子類。它是而不是。有些事情你可以用C[T]做,而你不能用C[U]做。

現在,你如何解決這個問題?

一種選擇是使課堂變(刪除+)。另一種選擇是,如果您採用方法參數,則還允許以及任何超類m[S >: T](s: S)。現在,如果T更改U,這沒什麼大不了的:的T超類也是U超類,並且該方法會奏效。 (不過,你就必須改變你的方法能處理這樣的事情。)

有了case類,得到它的權利,除非你把它不變的卻更難。我建議這樣做,並在其他地方推廣泛型和變異。但我需要看到更多的細節,以確保這可以用於你的用例。

+0

謝謝你的回答。然而,在這種情況下,您的解決方案對我無效。降低協方差並使特徵不變將起作用,但這不是我想要的。允許方法(或在我的案例類)採取超類型也不令人滿意。 我很好奇,爲什麼事情難以正確處理案例課。請注意,沒有_case_關鍵字的相同代碼工作得很好。 – lapislazuli 2012-03-08 16:50:45

+2

@lapislazuli - 因爲case類包含一個創建它們的伴隨方法(以'T'作爲參數),所以你必須遵守上面的方法限制。如果你不包含'case',那麼這個類並不意味着在接口中使用'T'的方法。 – 2012-03-08 16:57:05

+0

謝謝雷克斯,現在它對我有意義! – lapislazuli 2012-03-08 18:21:25

13

幾乎在那裏。在這裏:

scala> trait MyTrait[+T] { 
    | private case class MyClass[U >: T](c: U) 
    | } 
defined trait MyTrait 

這意味着MyClass[Any]適用於所有T。這就是爲什麼人們不能在該位置使用T的根源,但展示它需要更多的代碼,而不是我目前的心情。 :-)

相關問題