2

更新:我用一个更小更精确的例子重新表述了我的问题。

假设我们有以下定义:

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
                 ^

当使用 self 类型而不是 trait 时,也会发生同样的事情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]不被视为 type D[A]+T在 class 中使用协变注释时D,两个示例都有效。

有人可以解释这些例子失败的原因以及它们为什么要使用+T吗?

额外的问题:有没有办法让示例在没有的情况下运行+T

4

2 回答 2

3

考虑

class C[T]{ def f(t: T): T = t }

C[A with Y]说它将有一个f只会拿A with Y,只会返回A with YC[A]无法满足此请求的功能。因此,两者发生冲突。

由于类型声明的成功不取决于所涉及的任何类的方法的详细信息,Z1 with Z2或者任何其他组合方式C[A]C[A with Y]因此必须是错误的。

于 2012-06-28T23:02:06.063 回答
0

要查看方差问题,让我们向“TraitForX”添加一些方法。为简单起见,我将这些特征称为A1D1,并且我还将制作AD特征,再次为简单起见。我不知道你是如何想出有趣的结构的——我不知道 atrait甚至可以扩展 a 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 A1A1与顺便说一句相同),因此可以随后调用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 {}
}
于 2012-06-30T21:57:17.743 回答