如何在Scala中混合泛型和抽象类型?

时间:2011-08-14 12:48:14

标签: generics scala abstract-data-type

我想执行以下操作,但“Iterable [BASE]”将无法编译。在保持BASE为抽象类型的同时,正确的方法是什么?

trait Base
trait Meta {
    type BASE <: Base
}

trait EnumBase extends Base with Ordered[EnumBase]
trait EnumMeta extends Meta with Iterable[BASE] {
    override type BASE <: EnumBase
}

trait Manager extends EnumMeta {
    override type BASE <: MetaBase
}

我希望对于扩展EnumMeta并重新定义BASE的每个特征,该特征将是它自己的BASE的Iterable。到目前为止,我发现我可以这样做:

trait EnumMeta extends Meta with Iterable[EnumBase] {
    override type BASE <: EnumBase
}

trait Manager extends EnumMeta with Iterable[MetaBase] {
    override type BASE <: MetaBase
}

这是唯一(重复)方式,还是有更好的方法,只要它不需要返回到泛型参数?

[编辑]我刚刚发现如果泛型类型参数是自我类型,这将无效,如在Ordered [EnumBase]中。如果您尝试在名为MetaBase的派生类中更多地约束它,则得到:

illegal inheritance;  self-type MetaBase does not conform to
Ordered[MetaBase]'s selftype Ordered[MetaBase]

2 个答案:

答案 0 :(得分:1)

由于Iterable是通用的,因此选择泛型而非类型成员具有强烈的影响力,至少对于EnumMeta及更高版本而言。您可以从具有类型成员的祖先转到这样的泛型:

type EnumMeta[B <: Base] extends Meta with Iterable[B] {
  override type BASE = B
} 

使用其关系涉及类型成员的几个特征,您也可以考虑将类型成员放在封闭的上下文中而不是类本身中,例如

trait Context {
   type BASE <: Base
   type META <: Meta
   trait Base { def meta: META} 
   trait Meta { def base: BASE}
}

trait EnumContext extends Context {
   type BASE <: EnumBase
   type META <: EnumMeta
   trait EnumBase extends Base with Ordered[EnumBase] {}
    trait EnumMeta extends Meta  with Iterable[B] {}
}

(如果在顶层,特征BaseMeta为空,请删除它们,只有一个抽象成员type BASE - 和/或type META - 没有约束条件)

当你有一个你真正想要使用的上下文时,你可以将它混合在一起,或者让一个对象扩展它。

object EnumContext extends EnumContext  {
   type BASE = EnumBase
   type META = EnumMeta
}

答案 1 :(得分:1)

让代码编译的另一种方法是使用类型投影

trait Base
trait Meta {
  type BASE <: Base
}

trait EnumBase extends Base with Ordered[EnumBase]

trait EnumMeta extends Meta with Iterable[Meta#BASE] { // Type projection!
  type BASE <: EnumBase
}

trait Manager extends EnumMeta {
  // override type BASE <: MetaBase // You haven't defined type MetaBase yet
}

类型投影Meta#BASE告诉编译器你指的是BASE

不幸的是,自引用不起作用,

trait EnumMeta extends Meta with Iterable[EnumMeta#BASE] { ...

编译器抱怨,

[error] illegal cyclic reference involving trait EnumMeta
[error]   trait EnumMeta extends Meta with Iterable[EnumMeta#BASE] {
[error]                                                      ^

这种限制很不幸,并且类型参数优于类型成员。请参阅Didierd's answer以供参考。

(还有第二个问题,类型MetaBase未定义,但这与您的问题无关。)