[Scala] Scala 学习笔记 (11) - 隐式转换
程序员文章站
2022-06-15 12:09:02
...
隐式转换
隐式转换在工作中,能不用就不用,读代码难度很大,不利于team work。
场景:已有一个类,要基于这个类添加一个方法。
Java的实现思路:
如果要添加的方法很少,用继承或者装饰可以完成。
如果要添加的方法很多,最好的方法是使用代理。其中代理又分静态代理和动态代理:
静态代理:持有
动态代理:JDK,代理的是一个接口; CGLIB: 是一个类
Scala的实现思路:
隐式转换:即偷偷地,不知不觉地给你干了点啥。增强方法。
Scala代码实现:
示例一:普通狗转成牛逼的狗
定义一个普通的类
// 定义一个普通的狗
class Dog(val name:String)
再定义一个有属性有方法的类
// 再定义一个特殊的狗,这个类比上面的多一些属性和方法
class JoeyDog(val name:String) {
def speak(): Unit = {
println("wang wang wang.")
}
}
隐式转换
将普通的狗转换成牛逼的狗,这样普通的狗就可以调用牛逼的狗的方法了
object ImplicitApp {
def main(args: Array[String]): Unit = {
// 定义隐式转换函数: 普通2牛逼/普通To牛逼
// implicit 是一个
// 传进去一只普通狗,出去的时候是牛逼的狗
// 做法是new一个牛逼的狗,把普通狗的名字传进去
implicit def dog2JoeyDog(dog:Dog):JoeyDog = new JoeyDog(dog.name)
// 此时再new一个普通的狗出来,这条普通的狗就可以调用牛逼的狗的方法了
val dog = new Dog("Dog A")
dog.speak()
}
}
示例二:为Java的File类添加一个read方法
/**
* Java里面有一个File类,为File添加一个read方法可以直接读取内容
* 我们不能直接修改源码,通常可以通过隐式转换来实现
* 定义的RichFile类要把File类传进去
*/
class RichFile(val file:File) {
def read() = {
Source.fromFile(file.getPath).mkString
}
}
隐式转换,让File可以调用RichFile里面新添加的read方法
import java.io.File
import scala.io.Source
object FileImplicitApp {
def main(args: Array[String]): Unit = {
/**
* 定义一个隐式转换函数,把普通的File转成丰富的RichFile
* 其中File是java.io.File
*
*/
implicit def file2RichFile(file:File):RichFile = new RichFile(file)
val file = new File("test.txt")
val content = file.read()
println(content)
}
}
生产正确示例:整合ImplicitAspect类
以上两个示例阐明了隐式转换函数的用法,但是在实际生产中,上面的写法是比较忌讳的的。隐式转换函数的作用域是整合项目,隐式转换函数分散在各个文件中非常难找。通常的做法是抽取一个类(ImplicitAspect)出来,单独存放所有的隐式转换函数。
抽取一个ImplicitAspect类出来,把原来的隐式转换函数都移到这个类当中(原来各个类里面的隐式转换函数删除)
import java.io.File
// 这个类专门用来存放隐式转换函数
object ImplicitAspect {
// 把上面两个示例中的隐式转换函数拷贝过来,把原来scala类里面的隐式转换函数删除
implicit def file2RichFile(file:File):RichFile = new RichFile(file)
implicit def dog2JoeyDog(dog:Dog):JoeyDog = new JoeyDog(dog.name)
// 回到原来的文件中,import ImplicitAspect._ 即可
}
再回到原来的scala类中,添加一句话
import ImplicitAspect._
这样,原来的代码又可以正常运行了。
Spark的RDD源码里有很多隐式转换,可以参考。
上一篇: 【Scala编程_11】apply与 unapply
下一篇: 11 Scala 隐式转换