加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala中的逆变与协方差

发布时间:2020-12-16 19:22:00 所属栏目:安全 来源:网络整理
导读:我刚学会了 Scala.现在我对Contravariance和Covariance很困惑. 从这个page,我学到了以下内容: 协方差 也许子类型最明显的特征是能够用表达式中较窄类型的值替换较宽类型的值.例如,假设我有一些类型Real,Integerlt ;:Real,以及一些不相关的类型Boolean.我可
我刚学会了 Scala.现在我对Contravariance和Covariance很困惑.

从这个page,我学到了以下内容:

协方差

也许子类型最明显的特征是能够用表达式中较窄类型的值替换较宽类型的值.例如,假设我有一些类型Real,Integer&lt ;:Real,以及一些不相关的类型Boolean.我可以定义一个函数is_positive :: Real – >对Real值进行操作的Boolean,但我也可以将此函数应用于Integer类型的值(或Real的任何其他子类型).用较窄(后代)类型替换较宽(祖先)类型称为协方差.协方差的概念允许我们编写通用代码,并且在推理面向对象编程语言中的继承和函数语言中的多态时非常有用.

但是,我也从其他地方看到了一些东西:

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)

foo的参数x是逆变的;它期望一个类型为List [Dog]的参数,但是我们给它一个List [Beagle],这没关系

[我认为第二个例子也应该证明协方差.因为从第一个例子开始,我学会了“将此函数应用于Integer类型的值(或Real的任何其他子类型)”.相应地,这里我们将此函数应用于List [Beagle]类型的值(或List [Dog]的任何其他子类型).但令我惊讶的是,第二个例子证明了Cotravariance]

我认为两个人说的是同一个东西,但有一个证明了Covariance和另一个Contravariance.我也看到了this question from SO.但我仍然感到困惑.我错过了什么或者其中一个例子是错的吗?

解决方法

你可以将List [Beagle]传递给期望List [Dog]的函数与函数的逆变无关,它仍然是因为List是协变的并且List [Beagle]是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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读