scala 学习: 逆变和协变
scala 逆变和协变的概念网上有很多解释, 总结一句话就是
参数是逆变的或者不变的,返回值是协变的或者不变的。
但是为什么是这样的?
协变:

当s 是A的子类, 那么func(s) 是func(A)的子类。 也就是被参数化类型的泛化方向与参数类型的方向是一致的,所以称为协变。
个人理解的func(s) 是func(A)的子类的意思是: func(s)的返回值是func(A)的返回值的子类。
逆变:

同协变定义,但是是反过来,即当S是A的子类时,func(S)是func(A)的父类。
如下图所示:

为什么函数的参数是逆变 而函数的返回值是协变呢?

根据上面的解释: 入参是用来消费的, 如:animal > bird > dodo
假设有一个函数用来输出鸟类的叫声,func[-T], 这时 函数可以接受的参数为bird 和animal, 是合理的。
如果定义为func[+T], 函数接受的参数为 bird 和dodo, 对于参数为dodo类型来说,传另一个鸟如燕子, 则会出错。因此不符合要求。
scala> class Animal { val sound = "rustle" }
defined class Animal
scala> class Bird extends Animal { override val sound = "call" }
defined class Bird
scala> class Chicken extends Bird { override val sound = "cluck" }
defined class Chicken
假设你需要一个以Bird为参数的函数:
scala> val getTweet: (Bird => String) = // TODO
标准动物库有一个函数满足了你的需求,但它的参数是Animal。在大多数情况下,如果你说“我需要一个___,我有一个___的子类”是可以的。
但是,在函数参数这里是逆变的。如果你需要一个接受参数类型Bird的函数变量,但却将这个变量指向了接受参数类型为Chicken的函数,
那么给它传入一个Duck时就会出错。然而,如果将该变量指向一个接受参数类型为Animal的函数就不会有这种问题:
scala> val getTweet: (Bird => String) = ((a: Animal) => a.sound )
getTweet: Bird => String = <function1>
同理如返回值。
scala 学习: 逆变和协变的更多相关文章
- Scala 深入浅出实战经典 第81讲:Scala中List的构造是的类型约束逆变、协变、下界详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Java 逆变与协变
最近一直忙于学习模电.数电,搞得头晕脑胀,难得今天晚上挤出一些时间来分析一下Java中的逆变.协变.Java早于C#引入逆变.协变,两者在与C#稍有不同,Java中的逆变.协变引入早于C#,故在形式没 ...
- OOP中的逆变和协变
逆变和协变在存在于强类型语言中,尽管非常少提及.可是里面蕴含了面向对象的世界观.感谢和我一起讨论这个问题的人. 这里用了C#.Scala的语法作为演示样例.事实上逆变和协变的概念跟语言本身关系不大.事 ...
- Java中的逆变与协变
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- C#4.0新特性(3):变性 Variance(逆变与协变)
一句话总结:协变让一个粗粒度接口(或委托)可以接收一个更加具体的接口(或委托)作为参数(或返回值):逆变让一个接口(或委托)的参数类型(或返回值)类型更加具体化,也就是参数类型更强,更明确. 通常,协 ...
- Java中的逆变与协变(转)
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- Java 逆变与协变的名词说明
最近在研究Thinking in Java的时候,感觉逆变与协变有点绕,特意整理一下,方便后人.我参考于Java中的逆变与协变,但是该作者整理的稍微有点过于概念化,我在这里简单的说一下 我对于协变于逆 ...
- C# 逆变与协变
该文章中使用了较多的 委托delegate和Lambda表达式,如果你并不熟悉这些,请查看我的文章<委托与匿名委托>.<匿名委托与Lambda表达式>以便帮你建立完整的知识体系 ...
- .NET 4.0中的泛型逆变和协变
转载自:http://www.cnblogs.com/Ninputer/archive/2008/11/22/generic_covariant.html:自己加了一些理解 随Visual Studi ...
随机推荐
- CSS3-transition,过渡实例
过渡:transition[由Webkit内核浏览器提出] 通过CSS实现元素从一个样式渐变成另一个种. IE不支持,其他需后缀. transition:transition-property/dur ...
- 类似title的鼠标跟随事件
$(document).ready(function(){ // 创建一个div显示提示信息 var dropTitle = document.createElement("div" ...
- Lua与C++相互调用
{--1.环境--} 为了快速入手,使用了小巧快速的vc++6.0编译器 以及在官网下载了Lua安装包..官网地址{--http://10.21.210.18/seeyon/index.jsp--} ...
- 使用Python玩转WMI
最近在网上搜索Python和WMI相关资料时,发现大部分文章都千篇一律,并且基本上只说了很基础的使用,并未深入说明如何使用WMI.本文打算更进一步,让我们使用Python玩转WMI. 1 什么是WMI ...
- pt-find 使用实例
pt-find - Find MySQL tables and execute actions, like GNU find. 用法:pt-find [OPTION...] [DATABASE...] ...
- phoenix与spark整合
目的是将phoenix做存储,spark做计算层.这样就结合了phoenix查询速度快和spark计算速度快的优点.在这里将Phoenix的表作为spark的RDD或者DataFrames来操作,并且 ...
- [Eclipse] - Unicode properties editor
在properpties文件中使用中文,需要将文件转成unicode. eclipse安装插件:PropertiesEditor 下载地址: http://propedit.sourceforge.j ...
- 无线路由器WDS简要
A,B两台无线路由器,B去桥接A.在B中保持A相同的无线信道.在B中关闭DHCP.--A,B两台的SSID和无线安全设置都是独立的,无线安全可同可不同.
- putty连接ubuntu虚拟机缓慢问题的解决
vmware安装系统使用了ubuntu,安装后每次用PUTTY登录发现都到等很久,经过上网搜索,发现是Ubuntu安全机制导致的连接缓慢问题, 解决方法如下; 1. sudo vim /etc ...
- SQL Server 2012 创建数据库快照
不是所有的MSSQL数据库版本都支持数据库快照,只有Enterprise版本的才支持. 在其他版本上,以Business Intelligence Edition版本为例,创建快照时,会报如下错误 消 ...