有趣的隐式转换【scala】 两个案例
写在前面
好久没有更新文章了,今天简单写写源于scala中比较有意思的隐式转换。
在java中,我们如果需要为某个特定的类新增一个方法,即:功能增强,大致有几种方式:
- 继承
- 装饰器
- 代理(静态动态)
那么,在scala中,这个就可以使用隐式转换来达到。
隐式转换:
大致就是为类添加新方法,大致流程:
为某一个特定的类Dog,
写一个增强类RichDog(里面添加新方法),
写一个隐式声明 implicit def dogToRichDog(dog:Dog):RichDog = new RichDog(dog.name),
在特定的类需要使用到新方法之前,import 这个隐式声明之后就可以get到
对类功能进行增强,表面看不出来
比如:RDD.scala 源文件中就有大量的隐式转换,常见的reduceByKey方法 算子 其实本身不是自己定义的,而是增强而来
案例一:增强自己定义的类
简单说明:Dog本身没有speak方法,但是这里的话,需要隐式声明一下 :
implicit def dogToRichDog(dog:Dog):RichDog = new RichDog(dog.name)
这样Dog就能使用RichDog里面的方法,scala中其实RichDog本不是Dog的子类,但是import 这个隐式声明之后就可以get到
相当于父类调用子类对象,java可以直接用,这里需要手动import 隐式声明
/**
* Description:
* 隐式转换:
* 偷偷的增强,为类添加新的方法,表面看不出来
*
*
* @Author: 留歌36
* @Date: 2019/9/16 11:58
*/
object ImplicitDogApp {
def main(args:Array[String]): Unit = {
implicit def dogToRichDog(dog:Dog):RichDog = new RichDog(dog)
val dog = new Dog("小奶狗")
dog.speak()
}
}
class Dog(val name:String){
}
class RichDog(val dog:Dog){
def speak() = {
println(s"你好,我的名字是:${dog.name}")
}
}
案例二 增强java.io.File
简单说明:java.io.File 这个类本身没有read这个方法,通过自己编写一个RichFile 增强File的功能
import java.io.File
import scala.io.Source
/**
* Description: TODO
*
* @Author: 留歌36
* @Date: 2019/9/16 12:04
*/
object ImplicitFileApp {
def main(args:Array[String]): Unit ={
import ImplicitAspect.fileToRichFile
val file = new File("f:/hello.txt")
val context = file.read()
println(context)
}
}
class RichFile(val file:File) {
def read(): String ={
Source.fromFile(file.getPath).mkString
}
}
注意上面的是: import ImplicitAspect.fileToRichFile ,其实这里是写了一个隐式转换的切面类 的意思,当你的隐式声明变多之后,这样方便统一管理。定义的切面类:ImplicitAspect 如下:
import java.io.File
/**
* Description: TODO
*
* @Author: 留歌36
* @Date: 2019/9/16 12:11
*/
object ImplicitAspect {
implicit def fileToRichFile(file:File):RichFile = new RichFile(file)
implicit def dogToRichDog(dog:Dog):RichDog = new RichDog(dog)
}
拓展一:隐式参数
/**
* Description:
* 隐式参数: 生产上不建议使用
* 指的是在函数或者方法中,定义一个用implicit修饰的参数
* 此时:scala会尝试找到一个指定类型的,用implicit 修饰的
* 对象,即 隐式值,并注入参数
*
* @Author: 留歌36
* @Date: 2019/9/16 15:26
*/
object ImplicitParamApp {
def main(args: Array[String]): Unit = {
def testParam(implicit name:String): Unit = {
println(name + "~~~~~~~~~~~~")
}
// 测试1. 在没有定义 implicit val name 之前,需要显示的进行传参
// testParam("留歌36")
// 测试2.定义一个用implicit修饰的参数
// implicit val name1 = "留歌36"
// 这时,不用传递参数,测试OK
testParam
// 测试3:定义多个String类型的implicit修饰的参数
implicit val name2 = "留歌36"
implicit val name3 = "留歌37"
// 测试不Ok,因为编译器不知道该使用哪一个
testParam
}
}
拓展二:隐式类
/**
* Description: 隐式类
* 是指对类增加 implicit 关键字
* 作用:对类的增强
*
* @Author: 留歌36
* @Date: 2019/9/16 15:34
*/
object ImplicitClassApp {
def main(args: Array[String]) : Unit = {
// class Calculator(x:Int)这个类中 对于Int 类型的值,我们都是可以拥有 本个类中定义的方法的
implicit class Calculator(x:Int){
def add(a:Int)={
a + x
}
}
println(1.add(3))
}
}
ok,到这里就结束啦。有任何问题,可以留言告诉我~