我刚刚学习了Scala。现在,我对Convarivariance和Covariance感到困惑。
通过此页面,我学到了以下内容:
协方差
子类型化的最明显特征也许是在表达式中用较窄类型的值替换较宽类型的值的能力。例如,假设我有一些类型的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(Beagle@284a6c0)
参数x
的foo
IS contravariant
; 它期望一个类型为的参数List[Dog]
,但是我们给它一个List[Beagle]
,这没关系
[我认为第二个例子也应证明Covariance
。因为从第一个示例中,我学到了“将该函数应用于类型Integer
(或的任何其他子类型Real
)的值”。因此,相应地,在这里我们将此函数应用于type值List[Beagle]
(或的任何其他子类型List[Dog]
)。但令我惊讶的是,第二个例子证明了Cotravariance
]
我认为两个人在谈论同一件事,但是一个证明Covariance
,另一个Contravariance
。我也从SO中看到了这个问题。但是我还是很困惑。我是否错过了某些事情,或者其中一个例子是错误的?
您可以将a传递List[Beagle]
给期望a的函数与函数的List[Dog]
无关性,仍然是因为List是协变的,那List[Beagle]
就是a List[Dog]
。
相反,假设您有一个函数:
def countDogsLegs(dogs: List[Dog], legCountFunction: Dog => Int): Int
此功能计算狗列表中的所有腿。它具有接受狗并返回表示该狗有多少条腿的int的函数。
此外,可以说我们有一个功能:
def countLegsOfAnyAnimal(a: Animal): Int
可以数任何动物的腿。我们可以将函数作为函数参数传递countLegsOfAnyAnimal
给countDogsLegs
函数,这是因为,如果该事物可以计数任何动物的腿,它就可以计数狗的腿,因为狗是动物,这是因为函数是互变的。
如果看一下Function1
(一个参数的功能)的定义,那就是
trait Function1[-A, +B]
那就是说它们的输入是协变的,而输出是协变的。所以Function1[Animal,Int] <: Function1[Dog,Int]
既然Dog <: Animal
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句