我需要Scala的Generics帮助。
我有以下“抽象”特征:
trait Base[B <: Base[B,M], M <: Meta[B,M]] {
def meta: M
}
// Manages instances of a general type
trait Meta[B <: Base[B,M], M <: Meta[B,M]] {
// ...
}
// Manages Metas of a general type
trait Manager[M <: Meta[_,M]] {
def apply[N <: M](clazz: Class[N]): N
}
然后我想定义一些更具体的类型层次结构:
trait Thing[B <: Thing[B,M], M <: ThingMeta[B,M]] extends Base[B,M] {
// ...
}
trait ThingMeta[B <: Thing[B,M], M <: ThingMeta[B,M]] extends Meta[B,M]{
// ...
}
trait ThingManager extends *Manager[ThingMeta[_,_]]* {
// ...
}
最后一个声明给了我这个错误:
type arguments [ThingMeta[_, _]] do not conform to trait Manager's type parameter bounds [M <: Meta[_, M]]
我怎么能说ThingManager是所有ThingMetas的管理器,因此它本身并不采用类型参数。
答案 0 :(得分:2)
如果使用-explaintypes
进行编译,您会看到:
ThingMeta[_, _] <: Meta[_, ThingMeta[_, _]]?
显然,这不是真的。问题是Manager
根本不允许您自由选择M
的第二个类型参数:必须 M 本身 - 除非你定义一个特征或类,否则会导致递归。
也许Miles Sabin会提出一种方法来做到这一点 - 他经常以我认为不可能的方式让我感到惊讶 - 但是,或许最好使用抽象类型而不是类型参数,或放松边界。
答案 1 :(得分:2)
你通过删除绑定来放宽了Manager的声明,但这太过分了:
trait Manager[M <: Meta[_,M]] {
为什么不避免递归提及M
?使用以下行,您提供的代码将编译。
trait Manager[M <: Meta[_,_]] {
此解决方案类似于范式的解决方案 - 但我没有看到使用抽象类型的优势。唯一的好处是,如果他们允许你写下这样的东西:
type M = ThingMeta[_,M]
ThingManager
中的。
答案 2 :(得分:1)
比您的解决方案更受限制的解决方案:
trait Manager {
type M <: Meta[_,_]
def apply[N <: M](clazz: Class[N]): N
}
trait ThingManager extends Manager {
type M = ThingMeta[_,_]
}
答案 3 :(得分:0)
高阶类型怎么样?
trait Manager[MetaType[B,M] <: Meta[B,M]] {
def apply[N <: MetaType[_, _]](clazz: Class[N]): N
}
trait ThingManager extends Manager[ThingMeta]
抱歉,我没有可用的scala安装来检查这个。
修改即可。有一个scala安装。以前的代码不编译(对MetaType约束中的Meta参数的约束不满足)。但是这段代码确实:
trait Manager[
BaseType[B <: BaseType[B,M], M <: MetaType[B,M]] <: Base[B,M],
MetaType[B <: BaseType[B,M], M <: MetaType[B,M]] <: Meta[B,M]] {
def apply[N <: MetaType[_,_]](clazz: Class[N]): N
}
trait ThingManager extends Manager[Thing, ThingMeta] {}