2016-09-19 100 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]