简体   繁体   English

为什么Scala中的类型参数列表中的所有不变泛型类位置都不变?

[英]Why are all invariant generic class positions invariant in type parameter lists in Scala?

I'm a bit perplexed by the strictness of the typechecker below — it seems that the invariant T position of Inv[T] is also invariant within Variantish 's parameter list: 我对下面的类型检查器的严格性感到有点困惑 - 似乎Inv[T]的不变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]]
                             ^

Variant types can normally occur in what look like invariant argument-list positions legally, eg with object-protected visibility: 变体类型通常可以合法地出现在看似不变的参数列表位置,例如具有对象保护的可见性:

class Variantish[+T](protected[this] var v: Inv[T])

and it seems that the following would be just as typesafe: 并且似乎以下类似于类型安全:

class Variantish[+T, +TVar <: Inv[T]](protected[this] var v: TVar)

Need that check mentioned above be so strict? 需要上面提到的检查是如此严格?

From the language specification (emphasis mine), about conformance (ie T' is a super-type of T ): 从语言规范 (重点煤矿),约一致性(即T'是一个超级型T ):

Type constructors T and T′ follow a similar discipline. 类型构造函数TT′遵循类似的规则。 We characterize T and T′ by their type parameter clauses [a1,…,an] and [a′1,…,a′n] , where an ai or a′i may include a variance annotation, a higher-order type parameter clause, and bounds. 我们通过它们的类型参数子句[a1,…,an][a′1,…,a′n]表征TT′ ,其中aia′i可以包括方差注释,高阶类型参数条款和范围。 Then, T conforms to T′ if any list [t1,…,tn] -- with declared variances, bounds and higher-order type parameter clauses -- of valid type arguments for T′ is also a valid list of type arguments for T and T[t1,…,tn]<:T′[t1,…,tn] . 然后, T符合T′如果任何列表[t1,…,tn] -以宣变化,边界和高阶类型参数子句-有效的类型参数T′也是类型参数的有效列表TT[t1,…,tn]<:T′[t1,…,tn]

This is really difficult to understand (IMHO), but I believe it means that for Variantish to be covariant in T , you would have to be able to write 这真的很难理解(恕我直言),但我相信这意味着VariantishT是协变的,你必须能够写

Variantish[Dog, TVar] <: Variantish[Animal, TVar]

for any TVar for which Variantish[Animal, TVar] makes sense. 对于Variantish[Animal, TVar]有意义的任何 TVar But this doesn't even make sense (let alone have any truth value) for some of those TVar , such as Inv[Animal] . 但对于一些TVar ,这甚至没有意义(更不用说有任何真值),例如Inv[Animal] That's why it is forbidden in that place. 这就是为什么它被禁止在那个地方。

I didn't quite understand @cyrille-corpet's answer so I expanded it with some examples. 我不太明白@ 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 is valid since Animal <: Animal and AnimalInv <: AnimalInv are both true. a是有效的,因为Animal <: AnimalAnimalInv <: AnimalInv都是真的。

b is invalid since DogInv <: AnimalInv is false. b因为DogInv <: AnimalInv为false而无效。

c is valid since Dog <: Animal and AnimalInv <: AnimalInv are both true. c有效,因为Dog <: Animal and AnimalInv <: AnimalInv都是真的。

d is invalid since DogInv <: AnimalInv is false. d无效,因为DogInv <: AnimalInv为false。

So as these show TVar cannot be covariant. 因此,这些显示TVar不能协变。

Even in the case of d where the dynamic type is valid, it is not a subtype of the static type. 即使在动态类型有效的d的情况下,它也不是静态类型的子类型。

I suspect if we looked at all the places where we may be using TVar in Variantish then it doesn't need to be a type parameter. 我怀疑如果我们查看我们可能在Variantish使用TVar所有地方,那么它不需要是类型参数。 As @concat pointed out any variance errors you may encounted can be solved by using the object-protected access modifier. 正如@concat指出的那样,您可以通过使用受对象保护的访问修饰符来解决任何方差错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM