如果`T`是协变或逆变,那么`K>:T`和`K<:T`的方差是多少?

时间:2014-04-29 14:01:54

标签: scala covariance contravariance type-systems variance

如果T是协变或逆变,我可以确定以下方差:

K >: T

K <: T

我问这个是因为我在书中看到“scala编程”,它在代码中说:

trait Cat[T] {
   def meow[K]
}

K的位置是否定的,它必须是逆变的(让我们假设它不是非变量类型)。

由于我们不能仅使用单一类型K声明协方差或逆变,我们必须使用上限或下限,因此K可能是:

K >: T

K <: T

但我如何确定新类型是协变还是逆变?

3 个答案:

答案 0 :(得分:4)

正如我在评论中已经指出的那样,类型方差只能与类型参数相关联。类型本身不是协变的或逆变的或不变的。由于K未显示在Cat的类型参数列表中,因此CatK无差异。考虑:

trait Cat[T] {
  def meow[K]
}

class SiameseCat[T] extends Cat[T] {
  def meow[K] = println("loud meow")
}

class Foo
class Bar extends Foo
class Baz extends Bar

val barSiamese = new SiameseCat[Bar]

// COMPILATION ERROR: personality.analysis.demo.Bar <: personality.analysis.demo.Foo, but class SiameseCat is invariant in type T
val fooSiamese: SiameseCat[Foo] = barSiamese
// SAME
val bazSiamese: SiameseCat[Baz] = barSiamese

// NO ERROR
barSiamese.meow[Foo]
barSiamese.meow[Bar]
barSiamese.meow[Baz]
barSiamese.meow[Int]
barSiamese.meow[Unit]

可以说,在更宽松的语音中,你可以说一个类型是*变体,如果它显然是一个容器类型并只采用一个类型参数,例如List[T];也就是说可以说List是协变的,但这实际上扩展为List[T]T相关的协变。

但是,如果K确实出现在Cat的类型参数列表中,则可以将Cat声明为与K相关的协变量将+添加到KCat[T, +K],这将由编译器允许,因为K仅出现在Cat正文中的差异中立位置:

def meow[K]  // <-- meow doesn't take any parameters and returns `Unit`, so `K` is irrelevant with respect to variance

但是,如果您从K返回meow,则只能将Cat标记为K的不变量或协变量:

def meow: K  // contravariance made impossible

相反,这:

def meow(x: K)  // covariance made impossible

会强迫您使用Cat[T, -K](逆变)或Cat[T, K](不变)。

出于原因,无论是谷歌,还是看到我最近的答案@ why the first type parameter is defined as contravariant in Function1[-A, +B]?

答案 1 :(得分:1)

方法的类型参数,例如K中的def meow[K],不能是共变量或逆变量。该概念只能应用于类型的类型参数。

  

由于我们不能仅用单一类型K声明协方差或逆变,我们必须使用上限或下限

这也没有意义。我们可以声明MyClass中的K是协变的,如下所示:

class MyClass[+K]

这与下限/上限完全无关:您可以使用带或不带限制的变体类型参数。

答案 2 :(得分:0)

两种方差:

class X1
class X2 extends X1
class X3 extends X2

1)声明网站差异:

// covariant type-constructor:
class Cat[+T]

var cat : Cat[X2] = new Cat[X2]
var cat = new Cat[X3]
// cat = new Cat[X1] // not compiled

2)使用场地方差(按上限或下限):

//covariant variable for invariant type constructor:
class Cat[T]

var cat : Cat[_ <: X2] = new Cat[X2]
cat = new Cat[X3]
// cat = new Cat[X1] // not compiled

在方法或变量声明中常用的类型构造函数(容器)声明和使用站点差异中使用的Decalration-site方差。