前言

目的

(悄无声息、偷偷摸摸)增强已有的方法、函数、类

隐式转换是把双刃剑,用的好,增加代码健壮性,用的不好,代码执行流程难以理解。

隐式转换有三种

  • 隐式参数
  • 隐式类型转换

原有个A类型,现在转换成B类型,B是从A中拿到的,B要对A的功能进行增强,增强过程“悄无声息”,写代码时候感知不到。

  • 隐式类

其中隐式参数和隐式类型转换这两种为重点

三种类型隐式转换的实现

1.隐式参数

方法/函数的参数可以使用implicit来修饰

一个参数的隐式转换

object ImplicitApp {

  def main(args: Array[String]): Unit = {
    implicit val word = "欢迎学习spark"
    implicit val word2 = 123

    /**
     * 如果函数内的参数使用implicit,调用函数时
     * 调用是 参数如果不添加,会从上文去寻找 implicit string类型的变量
     * 例如 sayHello2 隐式参数为String类型,定义的word2为Int型就会忽略
     * 但是 string类型的变量只能有一个(不符合类型的隐式值不会有影响,只会去找符合参数类型的隐式值),否则会有下面的报错信息
     * --------------------------------
     * both value word2 of type String
     * and value word of type String
     * match expected type String
     * sayHello2
     * --------------------------------
     */

    sayHello(word)
    sayHello2

    def sayHello(msg: String): Unit = println(s"普通输出:${msg}")

    def sayHello2(implicit msg: String = "默认值"): Unit = println(s"隐式转换输出:$msg")
  }
}

2.隐式类型转换

需求:如何为一个已存在的类,添加一个新方法?

在java中可以使用Proxy 来解决

Scala可以用implict来完成

object ImplicitApp {

  def main(args: Array[String]): Unit = {
    val superman = new Superman("钢铁侠")
    superman.fly()

    //如何定义隐式转换函数,将人变成超人
    //定义好 implicit后,scala就会自动生成隐式转换
    //公式 implict def xToy (普通的X):牛逼的Y = new 牛逼的Y(.....)
    implicit def manToSuperman(man:Man):Superman = {
      new Superman(man.name)
    }

    val man = new Man("绿巨人")
    man.fly()
  }

}

//普通人无任何特意功能
class Man(val name:String)

//超人有特异功能,可以飞
class Superman(val name:String){
  def fly():Unit = {
      println(s"$name can fly")
  }
}

3.隐式类

import java.io.File

import scala.io.Source

object ImplicitApp {

  def main(args: Array[String]): Unit = {

    println(2.add("4"))

    /**
     * 首先scala中的Int类型是不存在add方法的
     * 我们定义了一个Int类型的隐式类,所有Int类型都会加强方法
     * 因此,在这里scala Int类型都会增强出add方法
     */
    implicit class Cal(x: Int) {
      def add(a: String) = s"隐式类拼接:调用值为:$a 函数输入值为:${x}"
    }

    /**
     * 同上面的道理,java的File方法没有read方法
     * 我们定义一个File类型的隐式类,就会为所有File类新增一个 read方法
     */
    val file = new File("data/file.txt")
    println(file.read)

    implicit class FileEnhance(file: File) {
      def read = Source.fromFile(file.getPath).mkString
    }
  }
}