隐式转换
隐式转换和隐式参数是Scala中两个非常强大的功能,利用隐式转换和隐式参数,可以提供类库,对类库的使用者隐匿掉具体的细节。
Scala会根据隐式转换函数的签名,在程序中使用到隐式转换函数接收的参数类型定义的对象时,会自动将其传入隐式转换函数,转换为另外一种类型的对象并返回,这就是“隐式转换”。
隐式转换需要使用implicit关键字。
使用Scala的隐式转换有一定的限制:
Spark源码中有大量的隐式转换和隐式参数,因此必须掌握隐式机制。
隐式转换函数
Scala的隐式转换最核心的就是定义隐式转换函数,即implicit conversion function。
定义的隐式转换函数,只要在编写的程序内引入,就会被Scala自动使用。
隐式转换函数由Scala自动调用,通常建议将隐式转换函数的名称命名为“one2one”的形式。
示例1:下面代码中定义了一个隐式函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package lagou.cn.part10class Num {}class RichNum (num:Num ) { def rich (): Unit ={ println("hello implicit!" ) } } object ImplicitDemo { implicit def num2RichNum (num:Num ):RichNum ={ new RichNum (num) } def main (args: Array [String ]): Unit = { val num=new Num num.rich() } }
示例2:导入隐式函数
1 2 3 4 5 package test.implicitdemoobject Int2String { implicit def int2String (num: Int ):String = num.toString }
下面代码中调用了String类型的length方法,Int类型本身没有length方法,但是在可用范围内定义了可以把Int转换为String的隐式函数int2String,因此函数编译通过并运行出正确的结果。
此示例中隐式函数的定义必须定义在使用之前,否则编译报错。
1 2 3 4 5 6 7 import test.implicitdemo.Int2String ._object ImplicitTest { def main (args: Array [String ]): Unit = { println(20. length) } }
通过import test.implicitdemo.Int2String._,将Int2StringTest内部的成员导入到相应的作用域内,否则无法调用隐式函数。
要实现隐式转换,只要在程序可见的范围内定义隐式转换函数即可,Scala会自动使用隐式转换函数。
隐式转换函数与普通函数的语法区别就是,要以implicit开头,而且最好要定义函数返回类型。
隐式转换案例:特殊售票窗口(只接受特殊人群买票,比如学生、老人等),其他人不能在特殊售票窗口买票。
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 lagou.cn.part10 class SpecialPerson(var name: String) class Older(var name: String) class Student(var name: String) class Worker(var name: String) object ImplicitDemoTwo { def buySpecialTickWindow(person: SpecialPerson): Unit = { if (person != null) { println(person.name + "购买了一张特殊票!") } else { println("你不是特殊人群,不能在此购票!") } } //定义一个隐式转换函数 implicit def any2SpecialPerson(any: Any): SpecialPerson = { any match { case any: Older => new SpecialPerson(any.asInstanceOf[Older].name) case any: Student => new SpecialPerson(any.asInstanceOf[Student].name) case _ => null } } def main(args: Array[String]): Unit = { val stu = new Student("jacky") val older = new Older("old man") val worker = new Worker("lisi") buySpecialTickWindow(stu) buySpecialTickWindow(older) buySpecialTickWindow(worker) } }
隐式参数和隐式值
在函数定义的时候,支持在最后一组参数 中使用 implicit ,表明这是一组隐式参数。在调用该函数的时候,可以不用传递隐式参数,而编译器会自动寻找一个 implicit 标记过的合适的值作为参数。
Scala编译器会在两个范围内查找:
当前作用域内可见的val或var定义隐式变量
隐式参数类型的伴生对象内隐式值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package lagou.cn.part10object DoublyDemo { def print (num:Double )(implicit fmt:String ): Unit ={ println(fmt format(num)) } def main (args: Array [String ]): Unit = { print(3.245 )("%.1f" ) implicit val printFmt="%.3f" print(3.24 ) } }