我刚刚学过Scala。现在我对逆变和协变感到困惑。Scala中的协变性与协方差
从这个page,我学到下面的东西:
协方差
也许亚型的最明显的特征是在表达一个更小的类型的值来代替一个更广泛类型的值的能力。例如,假设我有一些类型Real
,Integer <: Real
和一些不相关的类型Boolean
。我可以定义一个函数is_positive :: Real -> Boolean
,它的值为Real
,但我也可以将此函数应用于Integer
(或任何其他子类型为Real
)的值。用较窄(后代)类型替换较宽(祖先)类型称为covariance
。 covariance
的概念允许我们编写泛型代码,并且在推理面向对象的编程语言中的继承和函数式语言中的多态时非常有用。
但是,我也看到从其他地方的东西:
scala> class Animal
defined class Animal
scala> class Dog extends Animal
defined class Dog
scala> class Beagle extends Dog
defined class Beagle
scala> def foo(x: List[Dog]) = x
foo: (x: List[Dog])List[Dog] // Given a List[Dog], just returns it
scala> val an: List[Animal] = foo(List(new Beagle))
an: List[Animal] = List([email protected])
参数foo
x
为contravariant
;它预计类型List[Dog]
类型的论据,但我们给它一个List[Beagle]
,这没关系
[我认为是第二个例子也应该证明Covariance
。因为从第一个例子中,我了解到“将此函数应用于Integer
类型的值(或任何其他子类型Real
)”。因此相应地,我们在这里将此函数应用于List[Beagle]
(或List[Dog]
的任何其他子类型)类型的值。但令我惊讶的是,第二个例子证明Cotravariance
]
我认为两个人在说同一件事,但一个证明Covariance
和其他Contravariance
。我也看到了this question from SO。但是我仍然感到困惑。我错过了什么或者其中一个例子是错误的?
很好的解释。尽管'groomAnyAnimal'的返回类型应该是'Dog'来插入它,因为函数在它们的返回类型中是协变的并且仅在它们的参数类型中是逆变的。 – 2014-12-11 04:02:36
@stew你认为第二个例子的陈述有些不对吗? – CSnerd 2014-12-11 04:09:46
@CSnerd在你的第二个例子中,你想知道'x'是协变还是逆变。然而,正如炖菜所提到的,方差对于是否可以传递需要超类型的子类型没有任何关系(参见[Liskov Substitution Principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle))。在第二个例子中唯一的协变是List,因此'List [Beagle]'是List [Dog]的一个子类型。 – 2014-12-11 04:17:46