更新:我用更小更精确的例子重述了我的问题。
假设我们有以下定义:
class A
trait TraitForA extends A
class D[T]
trait TraitForD extends D[A]
然后我们可以创建一个像这样的对象:
scala> new D[A] with TraitForD
res0: D[A] with TraitForD = $anon$1@145d424
但我们无法创建以下对象:
scala> new D[A with TraitForA] with TraitForD
<console>:12: error: illegal inheritance;
anonymous class $anon inherits different type instances of class D:
D[A] and D[A with TraitForA]
new D[A with TraitForA] with TraitForD
^
当使用自我类型而不是extends
时,会发生同样的事情:
scala> trait TraitForD2 { self: D[A] => }
defined trait TraitForD2
scala> new D[A with TraitForA] with TraitForD2
<console>:12: error: illegal inheritance;
self-type D[A with TraitForA] with TraitForD2 does not conform to TraitForD2's
selftype TraitForD2 with D[A]
new D[A with TraitForA] with TraitForD2
^
上面的创作有什么(确切)错误?
我的猜测是D[A with TraitForA]
不被视为D[A]
类型。在类+T
中使用协变注释D
时,两个示例都有效。
有人可以解释一下示例失败的原因以及他们与+T
合作的原因吗?
加分问题:有没有办法让这些示例在没有+T
的情况下运行?
答案 0 :(得分:3)
考虑
class C[T]{ def f(t: T): T = t }
C[A with Y]
表示它只会f
A with Y
,只会返回A with Y
。满足此请求的函数无法满足C[A]
。因此两者发生冲突。
由于类型声明成功不取决于所涉及的任何类的方法的详细信息,Z1 with Z2
或任何其他组合C[A]
和C[A with Y]
的方法必定是错误。
答案 1 :(得分:0)
要查看方差问题,让我们为'TraitForX'添加一些方法。为简单起见,我会将这些特征称为A1
和D1
,并且为了简单起见,我还会制作A
和D
特征。我不知道你是如何设法得出有趣的结构 - 我不知道trait
甚至可以扩展class
,这是奇怪的,它是允许的!
trait A
trait A1 extends A { def schoko = 33 }
trait D[T] { def result: T }
trait D1 extends D[A] {
def result: A = new A {}
}
现在我们知道我们可以使用A1
的实例执行某项操作,但A
的实例无法实现。此外,D1
具有result
的具体实现。
仍然可以重现您的案例:
new D[A] with D1 // works.
new D[A with A1] { // works.
def result = new A with A1 {}
def test = result.schoko
}
您可以看到test
可以调用方法result
,因为D
使用A with A1
进行参数化(顺便提一下A1
),可随后致电schoko
。
以下内容永远不会起作用:
new D[A with A1] with D1 {
def test = result.schoko
}
编译器会说value schoko is not a member of A
,这意味着它拒绝接受D
的参数化。 result
中已实施D1
以返回A
的实例(不知道schoko
),因此此处存在固有冲突。
现在D
更改为
trait D[+T] { def result: T }
(所有其余的仍然如上),你只是'推迟'问题:
new D[A with A1] with D1
编译器现在抱怨error: overriding method result in trait D of type => A with A1
(您认为这有效,因为您实际上没有实现result
)。
因此,方差注释允许您执行之前无法做到的某些事情。如果您尚未实施result
,则完全可以实现以下目标:
trait D2 extends D[A]
new D[A with A1] with D2 {
def result = new A with A1 {}
}