2014-10-18 49 views
4

下面的代碼不會(在斯卡拉2.11)編譯:我怎樣才能別名協泛型類型參數

case class CovariantClass[+R](value: R) { 
    type T = R 
    def get: R = value 
} 

object Main { 
    def main(args: Array[String]): Unit ={ 
    println(CovariantClass[String]("hello").get) 
    } 
} 

的錯誤信息是:

Error:(4, 8) covariant type R occurs in invariant position in type R of type T 
    type T = R 
    ^

爲什麼我不能別名協變類型參數?如果我刪除行type T = R,代碼編譯並打印hello,所以別名似乎是問題。不幸的是,這意味着我不能爲更復雜的類型創建別名,例如type T = List[R]也不能編譯,儘管List是協變的。

回答

4

scala spec

一個類型別名的右手側始終處於不變的位置。

這意味着你不能創建別名T並在右側指定變量類型R。這同樣適用於List[R],因爲它也是協變的。

可以,但是提供了類型參數類型別名:

case class CovariantClass[+R](value: R) { 
    type T[+R] = List[R] 
    def get: R = value 
} 

如果你發現自己想別名類型參數R,你應該剛剛命名擺在首位別的東西。

+0

謝謝你的答案和引用scala規範。我同意重命名'R'而不是別名,但我喜歡爲''[ReturnValueInCaseOfFailure,R]''做一個別名。不幸的是,你提出的解決方法使'T'參數化,但它可能是我能達到我想要的最接近的。 – 2014-10-18 11:18:20

3

這是被禁止的,因爲它會允許一個不正確的程序,這總是規則。你可以把它改寫這樣的:

case class CovariantClass[+R](value: R) { 
    type T <: R 
    def get: R = value 
} 

至於它是如何把一個例子,可以這樣考慮:

case class CovariantClass[+R](value: R) { 
    type T = Int 
    def get: R = value 
    def put(x: T) {} 
    def put2(x: R) {} 
} 

由於T是如何定義的,它是不變的。這意味着它可以用於協變類型不能的地方,例如上面所見。請注意0​​編譯但put2沒有。

+0

有趣。儘管在這個例子中,「R」應該是「T」的下界,代碼打破了吧?另外,我不明白如何在不引入類型綁定的情況下打破它。這只是一個保守的設計選擇嗎?無論如何:謝謝你的例子。 – 2014-10-18 11:11:35

+0

@KuluLimpa我爲可能出現的問題添加了一個示例。這只是一個例子的開始,以顯示這如何與差異問題相關。如果您需要更多信息,請查看有關差異的問題 - 應該有些例子說明爲什麼某些職位的變體類型是非法的(我知道我以前寫過一些)。 – 2014-10-25 00:45:09

相關問題