如果你看到编译器实际上解释得很好:
: Foo1[String] with Foo2[String]> inherits different type instances of trait Foo:
Foo[Nothing,String] and Foo[String,Nothing]
new Foo1[String] with Foo2[String]
解释第一个:
new Foo1[String] with Foo2[Nothing]
看看这个例子:
scala> val x = new Foo1[String] with Foo2[Nothing]
x: Foo1[String] with Foo2[Nothing] = $anon$1@58651fd0
scala> val y:Foo[String, Nothing] = x
y: Foo[String,Nothing] = $anon$1@58651fd0
根据规范,多个with 特征的实例化从左到右发生。所以首先 Foo1 被实例化。做new Foo1[String] 会给你Foo[String, Nothing]。 with Foo2[Nothing] 给你Foo[Nothing, Nothing]。现在Foo 的第一个类型参数是协变的。简而言之,这是有效的:
scala> val a = new Foo[Nothing, Nothing]{}
a: Foo[Nothing,Nothing] = $anon$1@134593bf
scala> val b:Foo[String, Nothing] = a
b: Foo[String,Nothing] = $anon$1@134593bf
因此您可以使用 Foo[String, Nothing] 代替 Foo[Nothing, Nothing]。这使您能够实例化y。
如果发生:
new Foo1[String] with Foo2[String]
new Foo1[String] 给出Foo[String, Nothing]。 with Foo2[String] 给 Foo[Nothing, String]。而且它们都是矛盾的(由于它的第二个参数:
with Foo2[String] (Foo[Nothing, String]) 变为 Foo[String, String]。
scala> val p :Foo[String, String] = new Foo[Nothing, String]{}
p: Foo[String,String] = $anon$1@39529185
但是 Foo[String, String] 不能变成 Foo[String, Nothing]。 (val p :Foo[String, Nothing] = new Foo[Nothing, String]{} 失败)
因此错误。
变体中
如果 Foo 的第一个参数不是不变的,那么它就不起作用:
scala> trait Foo[A, +B]
defined trait Foo
scala> trait Foo1[A] extends Foo[A, Nothing]
defined trait Foo1
scala> trait Foo2[+B] extends Foo[Nothing, B]
defined trait Foo2
scala> new Foo1[String] with Foo2[Nothing]
<console>:11: error: illegal inheritance;
<$anon: Foo1[String] with Foo2[Nothing]> inherits different type instances of trait Foo:
Foo[Nothing,Nothing] and Foo[String,Nothing]
new Foo1[String] with Foo2[Nothing]
反方差
如果 Foo 在它的第二种类型上是逆变的,那么这两个语句都有效
scala> trait Foo[+A, -B]
defined trait Foo
scala> trait Foo1[+A] extends Foo[A, Nothing]
defined trait Foo1
scala> trait Foo2[-B] extends Foo[Nothing, B]
defined trait Foo2
scala> new Foo1[String] with Foo2[String]
res0: Foo1[String] with Foo2[String] = $anon$1@77468bd9
scala> new Foo1[String] with Foo2[Nothing]
res1: Foo1[String] with Foo2[Nothing] = $anon$1@51016012
它之所以有效,是因为现在:Foo[String, String] 可以变成 Foo[String, Nothing]