文档章节

scala-协变、逆变、上界、下界

jacksu
 jacksu
发布于 2015/11/20 07:46
字数 1177
阅读 2672
收藏 56

测试源代码

欢迎大家关注: scala工具库 ,里面包含各种库的测试用例和使用说明文档

协变逆变

B是A的子类,A是B的父类。

当我们定义一个协变类型List[A+]时,List[Child]可以是List[Parent]的子类型。

当我们定义一个逆变类型List[-A]时,List[Child]可以是List[Parent]的父类型。

##Scala的协变

看下面的例子:

    class Animal {}
    class Bird extends Animal {}
    class Animal {}
    class Bird extends Animal {}
    //协变
    class Covariant[T](t:T){}
    val cov = new Covariant[Bird](new Bird)
    val cov2:Covariant[Animal] = cov

cov不能赋值给cov2,因为Covariant定义成不变类型。

稍微改一下:

    class Animal {}
    class Bird extends Animal {}
    class Animal {}
    class Bird extends Animal {}
    //协变
    class Covariant[+T](t:T){}
    val cov = new Covariant[Bird](new Bird)
    val cov2:Covariant[Animal] = cov

因为Covariant定义成协变类型的,所以Covariant[Bird]是Covariant[Animal]的子类型,所以它可以被赋值给c2。

##Scala的逆变

将上面的例子改一下:

    class Animal {}
    class Bird extends Animal {}
    class Contravariant[-T](t: T) {
    }
    val c: Contravariant[Animal] = new Contravariant[Animal](new Animal)
    val c2: Contravariant[Bird] = c

这里Contravariant[-T]定义成逆变类型,所以Contravariant[Animal]被看作Contravariant[Animal]的子类型,故c可以被赋值给c2。

##下界lower bounds

如果协变类包含带类型参数的方法时:

    class Animal {}
    class Bird extends Animal {}
    class Consumer[+T](t: T) {
     	def use(t: T) = {}
    }

编译会出错。出错信息为 "Covariant type T occurs in contravariant position in type T of value t"。 但是如果返回结果为类型参数则没有问题。

    class Animal {}
    class Bird extends Animal {}
    class Consumer[+T](t: T) {
     	def get(): T = {new T}
    }

为了在方法的参数中使用类型参数,你需要定义下界:

    class Animal {}
    class Bird extends Animal {}
    class Consumer[+T](t: T) {
    	def use[U >: T](u : U) = {println(u)}
    }

这个地方比较复杂, 简单的说就是Scala内部实现是, 把类中的每个可以放类型的地方都做了分类(+, –, 中立), 具体分类规则不说了 对于这里最外层类[+T]是协变, 但是到了方法的类型参数时, 该位置发生了翻转, 成为-逆变的位置, 所以你把T给他, 就会报错说你把一个协变类型放到了一个逆变的位置上

所以这里的处理的方法就是, 他要逆变, 就给他个逆变, 使用[U >: T], 其中T为下界, 表示T或T的超类, 这样Scala编译器就不报错了 ##上界upper bounds

看一下逆变类中使用上界的例子:

    class Animal {}
    class Bird extends Animal {}
    class Consumer[-T](t: T) {
    	def get[U <: T](): U = {new U}
    }

可以看到方法的返回值是协变的位置,方法的参数是逆变的位置。 因此协变类的类型参数可以用在方法的返回值的类型,在方法的参数类型上必须使用下界绑定 >:。 逆变类的类型参数可以用在方法的参数类型上,用做方法的返回值类型时必须使用上界绑定 <:。

综合协变,逆变,上界,下界

一个综合例子:

    class Animal {}
    class Bird extends Animal {}
    class Consumer[-S,+T]() {
    	def m1[U >: T](u: U): T = {new T} //协变,下界
    	def m2[U <: S](s: S): U = {new U} //逆变,上界
    }
    class Test extends App {
    	val c:Consumer[Animal,Bird] = new Consumer[Animal,Bird]()
    	val c2:Consumer[Bird,Animal] = c
    	c2.m1(new Animal)
    	c2.m2(new Bird)
    }

##View Bound <%

Scala还有一种视图绑定的功能,如

    class Bird {def sing = {}}
    class Toy {}
    class Consumer[T <% Bird]() {
	    def use(t: T) = t.sing
    }

或者类型参数在方法上:

    class Bird {def sing = {}}
    class Toy {}
    class Consumer() {
    	def use[T <% Bird](t: T) = t.sing
    }
    class Test extends App {
	    val c = new Consumer()
	    c.use(new Toy)
    }

它要求T必须有一种隐式转换能转换成Bird,也就是 T => Bird,否则上面的代码会编译出错: No implicit view available from Toy => Bird. 加入一个隐式转换,编译通过。

    import scala.language.implicitConversions
    class Bird {def sing = {}}
    class Toy {}
    class Consumer() {
    	def use[T <% Bird](t: T) = t.sing
    }
    class Test extends App {
    	implicit def toy2Bird(t: Toy) = new Bird
    	val c = new Consumer()
    	c.use(new Toy)
    }

##Context Bound

context bound在Scala 2.8.0中引入,也被称作type class pattern。 view bound使用A <% String方式,context bound则需要参数化的类型,如Ordered[A]。 它声明了一个类型A,隐式地有一个类型B[A],语法如下:

    def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]

更清晰的一个例子:

    def f[A : ClassManifest](n: Int) = new Array[A](n)

又比如

    def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

##参考 Scala中的协变,逆变,上界,下界等

Scala的协变和逆变上界与下界

协变点和逆变点

© 著作权归作者所有

下一篇: scala工具库
jacksu
粉丝 9
博文 11
码字总数 6364
作品 1
西安
高级程序员
私信 提问
加载中

评论(5)

askHell
askHell
协变张量、逆变张量是张量分析的概念,用于将同一个“不变量”在不同的“坐标系”之间进行转换。
jacksu
jacksu 博主

引用来自“pseudo”的评论

文章里好多错误,不知道是复制的还是写的时候眼睛花了,写完也不审查下。对自己的博客都这么没有责任心
修改后的内容会更新到github中
jacksu
jacksu 博主

引用来自“pseudo”的评论

文章里好多错误,不知道是复制的还是写的时候眼睛花了,写完也不审查下。对自己的博客都这么没有责任心
会继续努力
__c
__c
scala里居然还有这种概念啊……学过相对论或者微分几何的应该知道逆变张量和协变张量是什么
pseudo
pseudo
文章里好多错误,不知道是复制的还是写的时候眼睛花了,写完也不审查下。对自己的博客都这么没有责任心
Scala的协变covariant(+),逆变contravariant(-),上界(:)

原文:https://my.oschina.net/xinxingegeya/blog/486671 Scala的协变(+),逆变(-),上界(<:),下界(>:) 协变covariant、逆变contravariant、不可变invariant 对于一个带类型参数的类型,比如...

u013063153
2017/11/09
0
0
Scala之类型参数化:Type Parameterization

Scala之类型参数化:Type Parameterization 本文原文出处: http://blog.csdn.net/bluishglc/article/details/52584401 严禁任何形式的转载,否则将委托CSDN官方维护权益! 型变:Variance 型...

bluishglc
2016/09/19
0
0
Scala版的生产者消费者模型&泛型中的协变(Covariance)与逆变(Contravar...

class BoundedBufferA : ClassManifest {var in = 0var out = 0var n = 0 val elems = new ArrayA def put(x: A) = synchronized {while (n >= N) wait()elems(in) = xin = (in + 1) % Nn = ......

开源中国驻成都办事处
2012/07/03
453
0
Kotlin 范型之协变、逆变

一. 类(Class) 与类型(Type) Kotlin 中类和类型是不一样的概念。 下图充分展示了它们的区别。 二. 型变 型变是指转换后的继承关系。 Kotlin 的型变分为逆变、协变和不变。 2.1 协变 如果 A ...

fengzhizi715
06/24
0
0
Scala 语言学习之泛型(7)

==> 泛型类 ---> T 可以代表任意类型 ==> 泛型函数 ---> 类型参数放在方法名之后 ==> 类型的上界和下界(Upper Bounds 和 Lower Bounds) ---> 用来定义泛型变量的范围 : ---> S <: T (上界......

科技小能手
2017/11/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

面向海量数据的极致成本优化-云HBase的一体化冷热分离

前言 随着业务的持续发展,业务数据库存储量会持续增长。通常数据量过亿时,就需要考虑做分库分表,或者选择扩展能力更好的NOSQL/NewSQL数据库,如HBase就可以单表支持PB级数据,足够满足大多...

阿里云官方博客
26分钟前
3
0
最新最全国内外架构开源技术干货资料

大家好,废话不多说,整理了精心收集了各类资源。 声明,如侵犯个人利益,请联系小编,会立即删除相关资料。 领取方式在文末 求转发列表 好了,由于资源太多啦,就不一一列举了。 大家按照下...

泥瓦匠BYSocket
28分钟前
6
0
springmvc jsp访问不了css

在jsp中引入css,一直报404错误,直接访问css,也无法访问 将css文件移出WEB-INF,因为处于安全性考虑,这个目录禁止外部访问。 当引用css时,可以直接用绝对路径${pageContext.request.conte...

沉迷于编程的小菜菜
30分钟前
4
0
android 系统版本 9.1网络请求遇到坑

网络请求异常: E/http: CLEARTEXT communication to plat.xunlinkeji.cn not permitted by network security policy 在res下新建一个xml目录 创建名为network_security_config.xml 文件 ,该......

MrLins
48分钟前
5
0
Istio 1.3 发布,HTTP 遥测不再需要 Mixer

> 原文链接:Istio 1.3 发布,HTTP 遥测不再需要 Mixer Istio 是 Google、IBM 和 Lyft 联合开源的服务网格(Service Mesh)框架,旨在解决大量微服务的发现、连接、管理、监控以及安全等问题...

米开朗基杨
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部