我对下面的类型检查器的严格性感到有点困惑 - 似乎T
的{{1}}位置在Inv[T]
的参数列表中也是不变的:
Variantish
变体类型通常可以合法地出现在看起来像不变的参数列表位置,例如具有对象保护的可见性:
scala> class Inv[T]
defined class Inv
scala> class Variantish[+T, +TVar <: Inv[T]]
<console>:12: error: covariant type T occurs in invariant position in type <: Inv[T] of type TVar
class Variantish[+T, +TVar <: Inv[T]]
^
似乎以下内容与typeafe一样:
class Variantish[+T](protected[this] var v: Inv[T])
上面提到的检查是否必须如此严格?
答案 0 :(得分:1)
从语言specification(强调我的),关于一致性(即T'
是T
的超类型:
类型构造函数
T
和T′
遵循类似的规则。我们通过类型参数子句T
和T′
来表征[a1,…,an]
和[a′1,…,a′n]
,其中ai
或a′i
可能包含方差注释,高阶类型参数子句和边界。然后,T
符合T′
if 任何列表[t1,…,tn]
- 具有声明的差异,边界和高阶类型参数子句 - 有效类型参数T′
也是T
和T[t1,…,tn]<:T′[t1,…,tn]
的有效参数列表。
这真的很难理解(恕我直言),但我认为这意味着Variantish
中的T
是协变的,你必须能够写
Variantish[Dog, TVar] <: Variantish[Animal, TVar]
任何 TVar
Variantish[Animal, TVar]
有意义。但对于TVar
中的某些人来说,这甚至没有意义(更不用说有任何真值),例如Inv[Animal]
。这就是为什么在那个地方被禁止的原因。
答案 1 :(得分:0)
我不太明白@ cyrille-corpet的回答所以我用一些例子扩展了它。
class Inv[T]
class Variantish[+T, +TVar <: Inv[T]]
trait Animal
class Dog extends Animal
class AnimalInv extends Inv[Animal]
class DogInv extends Inv[Dog]
val a: Variantish[Animal, Inv[Animal]] = new Variantish[Animal, AnimalInv]
val b: Variantish[Animal, Inv[Animal]] = new Variantish[Animal, DogInv]
val c: Variantish[Animal, Inv[Animal]] = new Variantish[Dog, AnimalInv]
val d: Variantish[Animal, Inv[Animal]] = new Variantish[Dog, DogInv]
a
有效,因为Animal
&lt;:Animal
和AnimalInv
&lt;:AnimalInv
都是正确的。
b
无效,因为DogInv
&lt;:AnimalInv
为false。
c
有效,因为Dog
&lt;:Animal
和AnimalInv
&lt;:AnimalInv
都是正确的。
d
无效,因为DogInv
&lt;:AnimalInv
为false。
因为这些节目TVar
不能协变。
即使在动态类型有效的d
的情况下,它也不是静态类型的子类型。
我怀疑如果我们在TVar
中查看了我们可能使用Variantish
的所有位置,那么它不需要是类型参数。正如@concat所指出的那样,您可以通过使用受对象保护的访问修饰符来解决任何方差错误。