我昨天在这里发布了这个问题的(looong(版本: 类型差异问题
长话短说,这个:
class A[-P, T <: P]
不编译(它抱怨,"P 出现在类型 <中的协变位置:T>
我认为这还不够。按照这种逻辑,这样的东西也应该是非法的:class B[+T <: String]
-B[String]
应该是B[Any]
的子类,但后者是无效的。
而且,这个:
class C[T, -P >: T]
实际上确实可以编译。这和上面A
不是一模一样吗?
这些是微妙的不同。
class Test[-P, T <: P]
说"让P
是一个逆变和无限变化的类型参数,A[Foo, Bar]
0是P
的一个子类型。也就是说,在检查类型是否对P
有效时,完全忽略T
。只有这样,T
才被约束为P
的子类型。这是非法的,原因你已经知道了。你可以从Test[Any, String]
开始,因为P
是无限逆变的,所以它可以变得Test[Nothing, String]
,突然间你就有了String <: Nothing
。
class tseT[T, -P :> T] // Code highlighters HATE him. Click to find out why.
说"让A[Nothing, Bar]
0是一个不变化且无界的类型参数,然后P
是一个受T
下界的逆变类型参数。这是一点点不同,因为这次P
的方差受到下界T
的约束。P
仍然逆变,但不能低于T
,否则会违反P >: T
。这是安全的,因为你可以从tseT[String, Any]
开始,然后P
只要它仍然是Bar
0的超类型,就只能向下变化,所以P
向下变化到Nothing
是非法的。
请注意,类型参数是从左到右处理的。这就是为什么第一个示例被声明为无效,而不是推断绑定P >: T
,因为在处理P
时尚未声明T
,并且这样的绑定无论如何都是前向引用。