隐式转换是Scala的强大特性之一,使得静态类型动态化,可以动态为现有类库添加定制化的功能。
隐式转换分四种:
隐式转换的规则:
- 如果代码无需隐式转换即可通过编译,则不会引入隐式转换,即便引入了也不会起作用(idea中显示为灰色);
- 不可存在二义性,如存在两个相同类型的隐式值时编译会报错
- 隐式操作不能嵌套使用(如 convert1(convert1(x)) ),即隐式转换从源类型到目标类型只会经过一次转换,不能经过多次隐式转换达到目标;
- 作用域原则,只在当前引入隐式转换的作用域内才起作用
使用方式:将对应的函数、类、参数、值标记为implicit
1、隐式转换函数
作用:增强一个类,添加本不存在的方法函数
格式:
隐式函数
1 2 3 | implicit def 函数名(参数):返回值类型 = { //函数体 } |
例1:
隐式函数例1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package lzr.implicitTest /** * Created by lizhirong on 2018/8/28. */ //Mathematics仅仅提供add函数 class Mathematics { def add(x : Int, y : Int) : Int = { x + y } } //下面是增强Mathematics类,添加一个subtract方法 class RichMathematics( val mathematics : Mathematics) { def substract(x : Int, y : Int) = { x - y } } object ImplicitFunctionTest { //将Mathematics转换为RichMathematics //Mathematics对象上可以直接调用RichMathematics定义的方法 implicit def mathematicsToRichMathematics(mathematics : Mathematics) = { new RichMathematics(mathematics) } // implicit def mathematicsToRichMathematics2(mathematics: Mathematics) = { // new RichMathematics(mathematics) // } def main(args : Array[String]) { val m = new Mathematics println(m.add( 20 , 7 )) println(m.substract( 20 , 7 )) //substract不属于 Mathematics,但可以使用 } } |
隐式转换函数的规则:
- 隐式转换函数的函数名可以是任意的,与函数名称无关,只与函数签名(函数参数和返回值类型)有关。
- 如果当前作用域中存在函数签名相同但函数名称不同的两个隐式转换函数(本例中的mathematicsToRichMathematics和mathematicsToRichMathematics2),则在进行隐式转换时会报错,即隐式转换的规则2
2、隐式类
在scala2.10后提供了隐式类,可以使用implicit声明类,相对于隐式函数更容易理解,代码更直观易懂
作用:增强对应的类
格式:
隐式转换
1 2 3 | implicit class 类名(参数){ //类主体 } |
例2:
隐式转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package lzr.implicitTest /** * Created by lizhirong on 2018/8/28. */ //Mathematics仅仅提供add函数 class Mathematics 2 { def add(x : Int, y : Int) : Int = { x + y } } object ImplicitClassTest { def main(args : Array[String]) { val m = new Mathematics 2 println(m.add( 20 , 7 )) println(m.substract( 20 , 7 )) //substract不属于 Mathematics,但可以使用 } //下面是隐式类的方式,给Mathematics类添加一个subtract方法 implicit class RichMathematics( val mathematics : Mathematics 2 ) { def substract(x : Int, y : Int) = { x - y } } } |
隐式类的规则
- 隐式类的主构造函数的参数有且仅有一个,是因为隐式转换是将一种类型转换为另外一种类型,源类型与目标类型是一一对应的
- 隐式类构造器只能带一个不是implicit修饰的参数

- 必须定义在另一个class/object/trait里面(不能独立定义)

3、隐式参数
格式:
隐式转换
1 2 3 | def 函数名( implicit 参数名:类型) : 返回值 = { //函数体 } |
例3:
隐式转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package lzr.implicitTest /** * Created by lizhirong on 2018/8/28. */ class Mathematics 3 { //柯里化,隐式参数要么只有一个,要么使用柯里化(柯里化时只能最后一个参数使用隐式implicit) // def add1(x: Int, implicit y: Int): Int = { // x + y // } // def add2(implicit x: Int)(y: Int): Int = { // x + y // } def add(x : Int)( implicit y : Int = 0 ) : Int = { x + y } def power( implicit y : Int) : Int = { y * y } } object ImplicitParamTest { def main(args : Array[String]) { val m = new Mathematics 3 println(m.add( 20 )( 7 )) println(m.add( 20 )) println(m.power( 7 )) } } |
隐式参数的规则:
- 隐式参数要么指定全部参数,要么使用柯里化(柯里化时只能最后一个柯里化内的参数(可多个)使用隐式implicit)
- implicit关键字在作用域内只能出现一次

- 匿名函数不能使用隐式参数

4、隐式值
格式:
隐式转换
例4:
隐式转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package lzr.implicitTest /** * Created by lizhirong on 2018/8/28. */ object ImplicitValueTest { implicit val y : Int = 2 implicit val z : Double = 4 def add(x : Int)( implicit y : Int = 0 ) : Int = { x + y } def power(x : Int)( implicit y : Double) : Double = { x * y } def main(args : Array[String]) { println(add( 20 )) println(power( 2 )) } } |
隐式值的规则:
- 相同类型的隐式值只能有一个

注:scala-2.10之后,推荐使用隐式类来给增强类的相关函数功能,相较于之前的隐式函数更容易理解,代码可阅读性更高