[Scala的协变和逆变]
Scala中协变和逆变主要作用是用来解决参数化类型的泛化问题。由于参数化类型的参数(参数类型)是可变的,当两个参数化类型的参数是继承关系(可泛化),那被参数化的类型是否也可以泛化呢?在Java中这种情况下是不可泛化的,然而Scala提供了三个选择,即协变、逆变和非变,解决了参数化类型的泛化问题。
协变和逆变
在Scala语言中,协变和逆变到处可见。如List,Queue等属于协变协变和逆变的一种。
协变和逆变使用“+”,“-”差异标记。当我们定义一个协变类型List[+A]时,List[Child]可以是List[Parent]的子类型,当我们定义一个逆变类型List[-A]时,List[Child]可以是List[Parent]的父类型
+B是B的超集,叫协变
-A是A的子集,叫逆变
假设有参数化特质List,那么可以有三种定义。如下所示:
(1) trait List [T]{}
非变。这种情况下,当类型S是类型A的子类型,则List [S]不可以认为是List [A]的子类型或父类型,这种情况和Java是一样的。
(2) trait List [+T]{}
协变。如果Sextends A (S为子类型,A为父类型),则List [S]为子类型,List [A]为父类型S <: A => List [S] <: List [A]。
(3) trait List [-T]{}
逆变。如果S extends A (S为子类型,A为父类型),则List [S]为父类型,List [A]为子类型,和协变互逆S <: A => Queue[S] >: Queue[A]。
那么,在Scala中如何定义协变逆变类呢,举例如下。
objectCovariantAndContravariantDemo {defmain(args: Array[String]): Unit = {//不变definv1: Invariant[Tiger] = newInvariant[Tiger]()//不可以赋值,编译器编译不通过definv2: Invariant[Cat] = inv1//协变defcov1: Covariant[Tiger] = newCovariant[Tiger]()//可以直接赋值defcov2: Covariant[Cat] = cov1//逆变defcont1: Contravariant[Cat] = newContravariant[Cat]()//可以直接赋值defcont2: Contravariant[Tiger] = cont1}/*** 定义一个不可变的类*/class Invariant[T] {}/*** 定义一个协变的类*/class Covariant[+T] {}/*** 定义一个逆变的类*/class Contravariant[-T] {}/*** 定义一个动物的类,具有行为(吃)*/class Animal {def eat() {println("Animal likeeat botany.")}}/*** 定义动物(猫)的类,具有行为(吃)*/class Cat extends Animal {override def eat() {println("Cat eatfish.")}}/*** 定义动物(老虎)的类,具有行为(吃)*/class Tiger extends Cat {override def eat() {println("Tiger eatmeat.")}}
}
上界和下界
类型的上界和下界,它们的含义如下。
1) U >: T
这是类型下界的定义,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。
2) S <: T
这是类型上界的定义,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)
协变、逆变结合上下界
栗子
协变 |
逆变 |
trait c1[+T] { def method[K >: T](x:K) = x } |
trait c1[-T] { def method [K <: T](x:K) = x } |
object c2 extends c1[Int] c2.method (3) // 3 c2.method (3.0) // 3.0 c2.method ("abc") // "abc" |
object c2 extends c1[Int] c2.method (3) // 3 c2.method (3.0) // 报错 c2.method "abc") // 报错 |
[Scala的协变和逆变]相关推荐
- Scala中协变(+)、逆变(-)、上界(:)、下界(:)简单介绍
对于一个带类型参数的类型,比如 List[T],如果对A及其子类型B,满足 List[B]也符合List[A]的子类型,那么就称为covariance(协变) , 如果 List[A]是 List[B ...
- spark笔记之Scala中的协变、逆变、非变
1.1. 协变.逆变.非变介绍 协变和逆变主要是用来解决参数化类型的泛化问题.Scala的协变与逆变是非常有特色的,完全解决了Java中泛型的一大缺憾:举例来说,Java中,如果有 A是 B的子类,但 ...
- Scala教程之:深入理解协变和逆变
文章目录 函数的参数和返回值 可变类型的变异 在之前的文章中我们简单的介绍过scala中的协变和逆变,我们使用+ 来表示协变类型:使用-表示逆变类型:非转化类型不需要添加标记. 假如我们定义一个cla ...
- Scala入门到精通——第二十一节 类型参数(三)-协变与逆变
本节主要内容 协变 逆变 类型通匹符 1. 协变 协变定义形式如:trait List[+T] {} .当类型S是类型A的子类型时,则List[S]也可以认为是List[A}的子类型,即List[S] ...
- scala 协变和逆变_Scala方差:协变,不变和逆变
scala 协变和逆变 In this post, we are going to discuss about Scala Variance and it's use cases. 在本文中,我们将讨 ...
- 7.scala初识 柯里化、隐式参数、隐式转换、视图边界、上界、下界、协变、逆变
1.前言: 学过java我们都知道,java中的继承是对类的增强,java中的代理.装饰是对对象方法的增强.而在scala中,隐式转换和隐式参数是Scala中两个非常强大的功能,隐式的对类的方法进行增 ...
- 不变(Invariant), 协变(Covarinat), 逆变(Contravariant) : 一个程序猿进化的故事
阿袁工作的第1天: 不变(Invariant), 协变(Covarinat), 逆变(Contravariant)的初次约 阿袁,早!开始工作吧. 阿袁在笔记上写下今天工作清单: 实现一个scala类 ...
- 上界与下界-- 视图界定--协变与逆变
1.上界与下界:Upper bound,lower bound 作用:规定泛型的取值范围 Int x ...
- C# 4.0中的协变和逆变(一)
在刚刚落下帷幕的PDC上,我们得到了很多振奋的消息,包括C# 4.0及VS2010等等.Anders Liu 已经 将C# 4.0 新特性白皮书翻译了 出来,那里面有非常详细的介绍. C#的发展是很快 ...
- .NET可变性解析(协变和逆变)
[一]何为可变性 可变性是.NET4.0中的一个新特性,可变性可分为 : 协变性.逆变性.不可变性. 那么在.NET4.0之前是否有可变性? 答案是肯定的,我们可以通过下面的几个实例来简单的了解一下. ...
最新文章
- Shiro第一个程序:官方快速入门程序Qucickstart详解教程
- 【无标题】ubuntu20.04 开机引导后黑屏 光标闪现 无法进入图形桌面的解决方案_Denis.Zzzzzzzz?的博客-CSDN博客_ubuntu20黑屏光标闪烁
- BIM机器人来袭、你害怕了吗
- 2016年湖南省第十二届大学生计算机程序设计竞赛
- EOS全球行南京站:降低用户及开发者门槛仍是2019 EOS关键词
- Excel 2016新增函数之IFS
- Python高级——GIL全局解释器锁问题
- 雅思阅读真经总纲_你们要的刘洪波《雅思阅读真经总纲》高清PDF扫描版来了!!...
- VB判断指定名字的进程是否存在函数
- FastDFS特性及问题思考
- sql 去除数据表中一列中字符串后边的空格...
- C++初学必练基础题【第四期】
- mysql 超级管理员权限_取得超级管理员权限
- 一个简单的新闻发布系统
- 为什么公司宁愿花 15k 重招一个新人,也不愿加薪 5k 留住老程序员?
- Layer 开启与关闭加载层
- wirehark数据分析与取证attack.pcap
- 搭建个人博客【搭建Hexo+Fluid博客并部署到GitHub/云服务器(阿里云/腾讯云)】
- 腾讯微信客服电话号码是多少呢/腾讯微信人工服务热线
- [渝粤教育] 西北工业大学 理论力学 参考 资料