Scala之隐式转换
概述
简单说,隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型。
隐式转换有四种常见的使用场景:
将某一类型转换成预期类型
类型增强与扩展
模拟新的语法
类型类
语法
隐式转换有新旧两种定义方法,旧的定义方法指是的“implict def”形式,这是Scala 2.10版本之前的写法,在Scala 2.10版本之后,Scala推出了“隐式类”用来替换旧的隐式转换语法,因为“隐式类”是一种更加安全的方式,对被转换的类型来说,它的作用域更加清晰可控。
接下来我们通过实例来了解这两种隐式转换的写法。前文提到,隐式转换最为基本的使用场景是:将某一类型转换成预期类型,所以我们下面的例子就以最这种最简单的场景来演示,它们都实现了:将一个String类型的变量隐式转换为Int类型:
“implict def”形式的隐式转换
package com.github.scala.myimplicit /**
* A demo about scala implicit type conversion.
* @author Laurence Geng
*/
object ImplicitDefDemo { object MyImplicitTypeConversion {
implicit def strToInt(str: String) = str.toInt
} def main(args: Array[String]) {
//compile error!
//val max = math.max("1", 2);
import MyImplicitTypeConversion.strToInt
val max = math.max("", );
println(max)
}
}
“隐式类”形式的隐式转换
package com.github.scala.myimplicit /**
* A demo about scala implicit type conversion.
* @author Laurence Geng
*/
object ImplicitClassDemo { implicit class MyImplicitTypeConversion(val str: String){
def strToInt = str.toInt
} def main(args: Array[String]) {
//compile error!
//val max = math.max("1", 2);
import com.github.scala.myimplicit.ImplicitDefDemo.MyImplicitTypeConversion._
val max = math.max("", );
println(max)
}
}
隐式类有如下几个限制:
They must be defined inside of another trait/class/object. They may only take one non-implicit argument in their constructor. There may not be any method, member or object in scope with the same name as the implicit class.
Note: This means an implicit class cannot be a case class.
隐式类与旧的隐式转换的语法(implicit def)是有细微的不同的,隐式类的运作方式是:隐式类的主构造函数只能有一个参数(有两个以上并不会报错,但是这个隐式类永远不会被编译器作为隐式类在隐式转化中使用),且这个参数的类型就是将要被转换的目标类型。从语义上这很自然:这个隐式转换类将包裹目标类型,隐式类的所有方法都会自动“附加”到目标类型上。
应用场景
转换成预期类型
对于这种使用场景实际上并不多见,实际意义也没有那么大。前文的代码就是这样这一场景的一个示例。
类型增强与扩展
真正让隐式转换大放异彩的是“类型增强”。这方面的示例是非常多的。
案例一:ArrayOps对Array的类型增强
一个典型案例是:Scala对Array对象进行的隐式转换。我们知道,Scala通过Predef声明了针对Array类型的两个隐式转换:一个是到ArrayOps的隐式转化,另一个是到WrappedArray的隐式转换。以前者为例,它为Array对象“添加”了大量的操作,这是通过隐式转换来”通明“的对一个类进行增强的典型案例!以下是Scala API文档中对这一技术细节的说明:
Two implicit conversions exist in scala.Predef that are frequently applied to arrays: a conversion to scala.collection.mutable.ArrayOps (shown on line of the example above) and a conversion to scala.collection.mutable.WrappedArray (a subtype of scala.collection.Seq). Both types make available many of the standard operations found in the Scala collections API. The conversion to ArrayOps is temporary, as all operations defined on ArrayOps return an Array, while the conversion to WrappedArray is permanent as all operations return a WrappedArray.
案例二:Spark中PairRDDFunctions对RDD的类型增强
如果你看一下Spark中的RDD以及它的子类是没有groupByKey, reduceByKey以及join这一类基于key-value元组的操作的,但是在你使用RDD时,这些操作是实实在在存在的,Spark正是通过隐式转换将一个RDD转换成了PairRDDFunctions, 这个动作是这样发生的:
首先在RDD的伴随对象中声明了从RDD到PairRDDFunctions的隐式转换:
然后在SparkContext中import了RDD的所有东西,使隐式转换生效。
模拟新的语法
这也是非常酷的一种应用场景。一个典型的应用场景就是Map中用于创建key-value元组的->符号,它就是一个隐式转换的产物。->不是 scala 本身的语法,而是类型 ArrowAssoc 的一个方法。这个类型定义在包 Scala.Predef 对象中。 Scala.Predef 自动引入到当前作用域,在这个对象中,同时定义了一个从类型 Any 到 ArrowAssoc 的隐含转换。因此当使用 1 -> “One”时,编译器自动插入从 1 转换到 ArrowAsso c转换。
类型类
类型类是一种非常灵活的设计模式,可以把类型的定义和行为进行分离,让扩展类行为变得非常方便。或者说如果我们想创建跨越类型的功能(即功能实现独立于类型去演变),那么这样的“功能”不是适合也不应该在主类型的层次结构上进行演变的,这时是使用类型类的绝佳场所。因为类型类是一个比较独立的语法,虽然它的实现需要使用到类型类,但是在本文中为了不止于失去焦点,我们不打算在这里详细介绍,而在接下来的一篇文章中进行专门的介绍。
隐式解析的搜索范围
这一部分的规则有些复杂,根据《Scala In Depth》所描述的,顶层的搜索逻辑是:
在当前作用域下查找。这种情形又分两种情况,一个是在当前作用域显示声明的implicit元素,另一个通过import导入的implicit元素。
如果第一种方式没有找到,则编译器会继续在隐式参数类型的隐式作用域里查找。
真正复杂的地方是什么叫一个类型的隐式作用域?一个类型的隐式作用域指的是“与该类型相关联的类型”的所有的伴生对象。
OK,那什么叫作“与一个类型相关联的类型”? 定义如下:
假如T是这样定义的:T with A with B with C,那么A, B, C的伴生对象都是T的搜索区域。
如果T是类型参数,那么参数类型和基础类型都是T的搜索部分。比如对于类型List[Foo],List和Foo都是搜索区域
如果T是一个单例类型p.T,那么p和T都是搜索区域
如果T是类型注入p#T,那么p和T都是搜索区域。
隐式参数
为什么把隐式参数单独拿出来放到最后讲是因为从用意上讲,隐式参数与我们前面讲述的隐式类型转化有很大的差异,虽然它涉及到了关键字implict,但是它做的是另外一件事情。隐含参数有点类似缺省参数,如果在调用方法时没有提供某个参数,编译器会在当前作用域查找是否有符合条件的 implicit 对象可以作为参数传入,不同于缺省参数,隐式参数的值可以在方法调用的前的上下文中指定,这是隐式参数更加灵活的地方。
object ImplicitParamDemo { object Greeter{
def greet(name:String)(implicit prompt: String) {
println("Welcome, " + name + ". The System is ready.")
println(prompt)
}
} def main(args: Array[String]) { implicit val prompt = ">" Greeter.greet("admin")
} }
Scala之隐式转换的更多相关文章
- scala自定义隐式转换
Scala自定义隐式转换 一.编写隐式转换类 /** * Author Mr. Guo * Create 2019/4/20 - 17:40 */ object StringImprovments { ...
- Scala学习——隐式转换
scala隐式转换 一.需求:为一个类添加一个新的方法 java:动态代理 scala:隐式转换 隐式转换例子: 1.man to superMan package top.ruandb.scala. ...
- 深入理解Scala的隐式转换系统
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
- Scala模式匹配| 隐式转换
1. 模式匹配 Scala中的模式匹配类似于Java中的switch语法,但是更加强大.模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分 ...
- 转载:深入理解Scala的隐式转换系统
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
- Scala之隐式转换implicit详解
假设我们有一个表示文本的行数的类LineNumber: class LineNumber ( val num : Int ) 我们可以用这个类来表示一本书中每一页的行数: val lineNumOfP ...
- Scala学习之路 (八)Scala的隐式转换和隐式参数
一.概念 Scala 2.10引入了一种叫做隐式类的新特性.隐式类指的是用implicit关键字修饰的类.在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换. 隐式转换和隐式参数是Scal ...
- 深入理解Scala的隐式转换
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
- scala的隐式转换
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
随机推荐
- c++11 auto 与 decltype 详解
转自: here 一. auto简介 编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型.然而做到这一点并非那么容易(特别是模板中),有时候根本做不到.为了解决这个问题 ...
- css3整理--Animation
animation语法: 1.动画的定义 @keyframes IDENT { from { Properties:Properties value; } Percentage { Propertie ...
- 【CF566C】Logistical Questions 点分
[CF566C]Logistical Questions 题意:给你一棵n个点的树,点有点权,边有边权,两点间的距离为两点间的边权和的$3\over 2$次方.求这棵树的带权重心. $n\le 200 ...
- 遍历DOM打平
html 模板 <div class="box"> <p>1</p> <p>2</p> <div> < ...
- bootstrapValidator多字段联合验证(如开始日期和结束日期中,开始日期不可晚于结束日期)
接触bootstrapvalidator时间不久,最近需要多个字段共同验证,网上查了一下未找到,查阅api文档,发现确实可以实现. 先看dom <div class="form-gro ...
- POJ-1143(状态压缩)
Number Game Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3432 Accepted: 1399 Descripti ...
- TOP100summit【分享实录-网易】构建云直播分发网络
本篇文章内容来自2016年TOP100summit网易视频云.网易杭州研究院服务端技术专家邵峰的案例分享.编辑:Cynthia 邵峰:网易视频云.网易杭州研究院服务端技术专家浙江大学计算机专业博士毕业 ...
- 泡泡一分钟:Automatic Parameter Tuning of Motion Planning Algorithms
Automatic Parameter Tuning of Motion Planning Algorithms 运动规划算法的自动参数整定 Jos´e Cano, Yiming Yang, Brun ...
- [No000012C]WPF(4/7)类型转换器和标记扩展[译]
介绍 之前讨论了WPF的基础架构,然后逐步开始学习布局面板,转换,介绍了不同的控件,容器,UI转换等.在这篇文章中,我将讨论每个创建XAML应用前的开发人员应该了解的关于XAML最重要的东西. 标记扩 ...
- Scss基础用法
Scss基础用法 一.注释用法: (1)//comment:该注释只是在.scss源文件中有,编译后的css文件中没有. (2)/! /:重要注释,任何style的css文件中都会有,一般放置css文 ...