当编译器需要为具有抽象类型参数的类解析清单时,我遇到了编译器问题。以下代码段显示了问题
trait MyStuff
trait SecurityMutatorFactory[X]{
def apply(x1:X,x2:X)
}
object Example{
trait LEdge[N]
{
type L1
}
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]}
val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]]
}
结果,编译器抛出以下类型错误:
type mismatch;
found : scala.reflect.Manifest[LEdge[MyStuff]]
required: Manifest[MyEdge[MyStuff]]
Note: LEdge[MyStuff] >: MyEdge[MyStuff], but trait Manifest is invariant in type T.
You may wish to investigate a wildcard type such as `_ >: MyEdge[MyStuff]`. (SLS 3.2.10)
val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]]
编译器级别发生了什么? ^
答案 0 :(得分:3)
好吧,我对这种模式并不熟悉:
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]}
但我倾向于将使用type
关键字定义的类型视为别名(概念),而不是对实施的保证(编辑更确切地说,我相信type
在原型设计/指定方面提供了保证,但是在实际需要用它所基于的特征/类替换别名之前,不会生成AST /代码。因此,即使编译器在其错误消息中声明:
LEdge[MyStuff] >: MyEdge[MyStuff]
我不确定在字节码级别它是否相应地使用interfaces / methods / etc实现MyEdge
。因此,它可能无法识别LEdge和MyEdge之间的通缉关系,最终:
found : scala.reflect.Manifest[LEdge[MyStuff]]
required: Manifest[MyEdge[MyStuff]]
(并且,是否缺少包scala.reflect.
提示?(1))
关于您的代码,您如何使用a
?无论如何,如果以下是您的意图,请使用:
trait MyEdge[X] extends LEdge[X] {
type L1 = SecurityMutatorFactory[X]
}
相反,它确实编译(scala 2.10)...(编辑我刚才注意到dmitry已经告诉过了)...在运行时我做了什么,我不知道!< / p>
作为一个值得注意的项目,在{2}之后不推荐使用Manifest
;因此您可能更喜欢使用scaladoc中描述的TypeTag[T]
。
修改强>
(1)我怀疑发生以下情况:
- 在句法分析阶段,编译器将字面注册为您指定的内容,即implicitly
方法将返回 a Manifest[MyEdge[MyStuff]]
。
- 通过代码生成阶段,别名“协调”到最近的类或特征;在implicitly
的情况下,结果的类型Manifest[MyEdge[MyStuff]]
变为特征scala.reflect.Manifest[LEdge[MyStuff]]]
- 由于Manifest
中涉及的类型推断的某些限制以及类型参数中的类型“别名”,但是,某些指定的要求Manifest[MyEdge[MyStuff]]
仍然保持其原始形状
- (这是纯粹的猜想,因为我没有读过这个答案的Scala编译器源代码)编译器一方面会有正确的AST /代码,但是一个方法原型/规范仍然在它的raw / literal下另一方面是形状;这不适合它会发出错误。
希望有帮助...
答案 1 :(得分:3)
正如其他人所说,问题来自
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] }
type F[X] = ...
形式的声明引入了类型同义词,即现有类型的新名称。他们不构建新的特征或类。但是,LEdge[X] { type L1 = SecurityMutatorFactory[X] }
正在构建一个新的匿名类。所以你的例子是 approxlly 等同于
trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] }
(这是您最想要的)但示例中的原始定义是定义匿名类的同义词,而不是定义新类MyEdge[X]
。因此,在示例中,新类实际上不会被称为MyEdge
。构造隐式清单时,编译器将类型同义词替换为基础类型,但无法为其构造清单,因为该类型是匿名的。
用正常的扩展名定义替换MyEdge
声明:
trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] }
或与普通类型同义词:
type MyEdge[X] = LEdge[X]
都成功编译。
以下是为匿名类生成隐式清单失败的具体原因。
在语言规范类型中,BaseType { ... }
形式的经历被称为精炼类型。
根据语言规范,精炼类型的清单只是其基类的清单。然而,这无法进行类型检查,因为您要求Manifest[LEdge[MyStuff]{ type L1 = SecurityMutatorFactory[X] }]
,但算法返回Manifest[LEdge[MyStuff]]
。这意味着您只能在逆变位置中为具有细化类型的类型构造隐式清单。例如使用:
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] } => AnyRef
在你的例子中,允许它编译,虽然它显然不是你所追求的。
构造隐式清单的完整算法在语言规范的7.5节末尾给出。第6条涵盖了这个问题:
6)如果T是精化类型T'{R},则为T'生成清单。 (也就是说,改进从未在清单中反映出来。)