Scala之类型参数化:Type Parameterization
来源:互联网 发布:莉莉柯林斯长相知乎 编辑:程序博客网 时间:2024/05/19 00:09
Scala之类型参数化:Type Parameterization
本文原文出处: http://blog.csdn.net/bluishglc/article/details/52584401 严禁任何形式的转载,否则将委托CSDN官方维护权益!
- Scala之类型参数化Type Parameterization
- 型变Variance
- 不变 Invariant
- 协变Covariant
- 逆变Contravariant
- 类型参数的边界控制
- 下界Lower Bound
- 上界Upper Bound
- 视界View Bound
- 上下文边界Context Bound
型变:Variance
型变试图在规范和回答这样一个问题:如果T’是T的一个子类,那么Container[T’]应该被看做是Container[T]的子类吗?对于这个问题有三种可能的结果,它们分别如下:
不变: Invariant
“不变”性表述为:虽然T’是T的一个子类,但是Container[T’]和Container[T]之间无任何关联,不存在任何父子关系。
协变:Covariant
协变是比较符合人们的正常思维的,因此理解起来并不困难,简单解释就是:如果T’是T的一个子类,那么Container[T’]应该被看做是Container[T]的子类。下面的例子展示了协变[+T]的特性。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
逆变:Contravariant
逆变正好是协变的”反”方向:如果T’是T的一个子类,那么Container[T’]应该被看做是Container[T]的父类。这初看起来是非怪异并不符合情理的。在列举它的适用场景之前,我们同样来先看一下解释逆变的例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
很显然,上述例子中AnyRef是String的父类,但是Contravariant[AnyRef]则变成了Contravariant[String]的子类,从而可以进行赋值操作(变量声明为父类型,引用的是子类型实例)
逆变初看上去有些离经叛道,对于逆变的合理性,本系列有一篇专门的文章: Scala之“逆变”合理性的思考 ,对逆变进行了深入的思考。
类型参数的边界控制
在引入了范型之后,有时候我们需要对接受类型的范围进行一些限制,特别在引入了协变和逆变之后,更需要对于协变的下界和逆变的上界进行界定。
下界:Lower Bound
表述形式: U >: T
这种表述的含义是:U必须是类型T或T的父类。>:有点类似>=的意思。
如前所属,协变往往需要用到下界,例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
上述示例中Consumer是伴随类型T协变的,而f1的类型是Function1[-T1,+R],即要求类型T是逆变的,这样函数f1和类Consumer对类型T的要求就产生了冲突,比如Consumer可以声明使用T的一个子类型,而这个子类型是不能适用到f1上的。为了解决这个问题,我们可以针对f1的类型参数进行下界控制。
Scala官方文档中也有一个下界的使用示例:http://docs.scala-lang.org/tutorials/tour/lower-type-bounds
上界:Upper Bound
表述形式: S <: T
这种表述的含义是:S必须是类型T或T的子类。<:有点类似<=的意思。
scala官方文档中有一个上界的使用示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
在这个例子中我们注意第12行,如果没有上界声明:T <: Similar
,被声明为T的实例e是不能调用isSimilar方法的。
视界:View Bound
表述形式: A <% B
这种表述的含义是:类型A必须“可被视为”类型B,“可被视为”的意思就是存在一个将类A转换为类型B的隐式转换!下面这段示意代码演示的就是把类型A的实例当作了类型B去使用,因为存在一个从A到B的隐式转换。
- 1
- 1
而实际上,上述代码会被编译为:
- 1
- 1
在scala的类库中有这样典型的应用:
- 1
- 1
对于任何可以隐式转换为Ordered[A]类型的类型A,都可以直接使用比较大小的方法<。
注:Scala社区已不再推荐使用视界: https://github.com/scala/scala/pull/2909
上下文边界:Context Bound
让我们通过如下一段示例代码来了解一下Context Bound:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
sortBy1和sortBy2的效果是一样的,即针对一个集合,依据一个函数,把集合中的每个元素转换成另外一种类型的值,然后根据转化后的类型的排序规则( Ordering[B]的一个实例)进行排序。sortBy1是一种直白写法,而sortBy2是一种从语法上更为简洁的实现,或者说sortBy2实际上会被编译成sortBy1的形式。
简单地说,当我们看到一个Context Bound时,有两点我们应该立刻想到,以这里的[B : Ordering]为例:
- 方法已经自动引入了一个隐式参数implicit ord: Ordering[B]
- 如果在方法中需要使用这个隐式参数,可以通过Predef定义的方法implicitly来获取,如本例中做的那样:implicitly[Ordering[B]]
每当我们使用到Context Bound时,我们都可以通过上述的转换来理解Context Bound。当然,当你已经非常了解这中间发生的故事之后,你会就会适应这种简洁的语法而不再需要在脑袋里进行这种转换转换。
关于View Bound和Context Bound,可以参考Scala官方文档的一篇文章: http://docs.scala-lang.org/tutorials/FAQ/context-and-view-bounds.html
参考:
https://twitter.github.io/scala_school/zh_cn/type-basics.html
http://www.spoofer.top/2016/03/12/scala-%E5%8F%98%E4%B8%8E%E7%95%8C
- Scala之类型参数化:Type Parameterization
- Scala之类型参数化:Type Parameterization
- Scala - Type parameterization
- Scala入门之类型参数
- Scala入门之高级类型:this.type
- Scala 抽象类型Type
- Scala类型 8:type 关键字
- scala类型参数化以及上下界
- 【Scala学习笔记】类型参数化数组
- Scala学习笔记7 - 类型参数化
- scala------类型参数
- Scala类型参数
- Scala中的类型参数
- scala类型参数
- Scala类型参数(一)
- Scala类型参数(二)
- Scala 隐式类型之隐式参数
- Scala类型参数——泛型之协变
- poj题目分类
- 线程和socke
- 开始PHP的学习!
- ArrayList和LinkedList的简单实现
- Objective
- Scala之类型参数化:Type Parameterization
- 闭包
- 网页版2048实战--简介及构建页面
- Linux yum安装包的更新列表
- python实现动态规划求解给定矩阵的和最大的子数组(矩阵中数字正负均存在)
- 一篇文章看明白 HTTP,HTTPS,SSL/TSL 之间的关系
- spring源码(7)alias标签的解析
- 关于UGUI的个人优化总结
- Mac下git通过SSH连接本地服务器