码迷,mamicode.com
首页 > 其他好文 > 详细

逆变和协变的意义

时间:2015-07-14 17:57:06      阅读:435      评论:0      收藏:0      [点我收藏+]

标签:逆变   强类型语言   

逆变和协变在存在于强类型语言中,虽然很少提及,但是里面蕴含了对问题的描述。感谢和我一起讨论的人。

这里,使用C#、Scala中都包含逆变的参数声明方式。

一、逆变的定义

逆变的参数可以由指定的类型的子类型代替,Scala中的逆变声明:Function1[-A,+B] ;参数可以使用A类型或者A类的子类型。

二、协变与逆变的用途不同

1.语义

常见的地方用在Function的传入参数中,Function1[-A,+B]

输入的逆变表示“只要满足这种功能即可”,所以满足的功能,在A的子类中都有,逆变强调的是功能——“能做什么”。

顺便看下协变,输出协变,协变强调的是类型,A类型可以代替父类,如牛肉是肉。协变强调的是“是什么”。

2.刀和肉

类型:食品<-肉<-牛肉。武器<-刀<-牛肉刀。(<-表示继承关系:父类<-子类)

情景:函数FunctionX需要一把刀(强调刀的功能),会生产出肉。大致的定义为FunctionX[A,B],普通刀(刀类)会生产出普通肉(肉类),牛肉刀会生产出牛肉。

A的类型?B的类型?如何确定

A的类型可以为刀和牛肉刀,因为牛肉刀也是刀。甚至说刀的子类能够满足,从继承来讲刀的子类都是刀。

所以A的类型应该为逆变——-刀(刀和子类)

因为做出的是肉,所以B类型肯定包含肉,但不确定是牛肉。所以我们可以设定返回为B类型。

对于这个情景,我们对FunctionX的最终定义为:FunctionX[-刀,+肉]

协变呢?

我们没有看到协变,实际上在C#和Scala中,我们设定一个类型 食品 来接收FunctionX的返回值也不会报错。因为所有的返回类型在语言中都被声明为协变了,也就是说实际的定义是FunctionX[-刀,+肉]。这么做的原因是:如果我返回了一个肉,那么这个肉一定是食品,我总能用返回类型的父类型代替返回的对象。

三、另外的例子

ICompareable<in T>强调“可比较”这一功能,是逆变。

IEnumerable<out T>强调的是“可数的”类型,是协变。拿List<T>说明,List<肉>表示“我放了肉在列表里面”,可以说"我放了食品在列表里面"是没错了,即可以使用List<食品>代替。但是不能说“我放了牛肉在列表里面”,所以用List<牛肉>代替是不对的。

逆变和协变的意义

标签:逆变   强类型语言   

原文地址:http://blog.csdn.net/u012289636/article/details/46880745

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!