有趣的隐式转换【scala】

写在前面

好久没有更新文章了,今天简单写写源于scala中比较有意思的隐式转换。
在java中,我们如果需要为某个特定的类新增一个方法,即:功能增强,大致有几种方式:

  1. 继承
  2. 装饰器
  3. 代理(静态动态)

那么,在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,到这里就结束啦。有任何问题,可以留言告诉我~

posted @ 2019-09-16 12:46  liuge36  阅读(124)  评论(0编辑  收藏  举报