2016-09-19 73 views
1

我有以下層次結構,我想定義任何Description列表,但無法弄清楚它的參數類型。斯卡拉高級存在類型

abstract class Context 
class Local extends Context 
class Browsing extends Context 

abstract class Fruit[C <: Context] 
class Apple[C <: Context](id: Int) extends Fruit[C] 
class Banana[C <: Context](id: Int) extends Fruit[C] 

abstract class Description[U[X <: Context] <: Fruit[X]] // U can't be covariant 
class Apples extends Description[Apple] 
class Bananas extends Description[Banana] 

基本上,我想這樣的事情(不按原樣編譯):

val l: List[Description[_]] = List(
    new Apples, 
    new Bananas 
) 

任何方式來實現這一目標?

+0

你怎麼指望使用'l'? – talex

+0

請參閱http://stackoverflow.com/questions/32182694/how-to-define-an-existential-higher-kinded-type-in​​-scala或http://stackoverflow.com/questions/28176807/suppressing-unchecked-警告更高級的存在型 –

+0

實際上,我可以使用超類作爲沒有參數類型的'Description'並使用這些方法。但是在'Description'裏面,我引用了其他使用'U'參數化的對象,因此我們不得不爲這些對象創建超類(以及它們的子類......它是一個整體層次結構)。唯一的一點是儘可能多地保留關於類型的信息,而不需要創建任何額外的抽象層。 – olivier

回答

4

你需要做的是這樣的:

abstract class Description[+U[X <: Context] <: Fruit[X]] 

然後它會工作:

scala> List(new Apples, new Bananas) 
res40: List[Description[Fruit]] = List([email protected], [email protected]) 

爲什麼你的情況下,失敗的原因是:當你做List(new Apples, new Bananas),因爲編譯器嘗試找到ApplesBanana的最小上限(LUB)。即LUB爲Description[Apple]Description[Banana]。所以你需要的是Description[_ >: Banana with Apple <: Fruit]

由於編譯器錯誤正確地說:Apple <: Fruit(當然蘋果>:蘋果香蕉)。但是Description[Apple]只會是Description[_ >: Banana with Apple <: Fruit]的子類型,如果Description在其類型參數中是共同變體。

PS:協方差使我們有這種能力: 如果A <: B然後爲M[+T],M[A] <: M[B]

對於禁忌方差M[-T]M[A] >: M[B]