Cris 的 Scala 笔记整理(十):隐式转换

733 阅读3分钟

10. 隐式转换

隐式转换函数是以implicit关键字声明的带有单个参数的函数。这种函数将会自动应用,将值从一种类型转换为另一种类型

① 隐式转换最佳入门案例

首先看下面的代码

如果想要转换成功,就需要借助隐式转换函数

为了更好的理解,我们看看反编译后的字节码文件,底层编译器是如何隐式转换函数的

根据需求我们可以将任意数据类型的对象转换为我们想要的数据类型,以及进行处理

implicit def func2(num: Long): Int = {
  (num - 1).toInt
}

val num2: Int = 10L
println(num2) // 9

② 隐式转换的细节

  1. 隐式转换函数的函数名可以是任意的,隐式转换与函数名称无关,只与函数签名(函数参数类型和返回值类型)有关。

  2. 隐式函数可以有多个(即:隐式函数列表),但是需要保证在当前环境下,只有一个隐式函数能被识别

③ 强悍的隐式转换丰富类库功能

如果需要为一个类增加一个方法,可以通过隐式转换来实现。(动态增加功能)比如想为 Oracle 类增加一个 delete 方法

看看底层编译器的魔术

细节

在当前程序中,如果想要给 Oracle 类增加功能是非常简单的,但是在实际项目中,如果想要增加新的功能就会需要改变源代码,这是很难接受的。而且违背了软件开发的 OCP 开发原则

在这种情况下,可以通过隐式转换函数给类动态添加功能

④ 隐式值

隐式值也叫隐式变量,将某个形参变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省参数

示例代码

细节练习

  • 以下代码的函数命名编译器如何定义

看看底层编译器的字节码文件

  • 隐式值细节

    总结

    1. 隐式值的优先级高于默认值

    2. 当匹配到多个隐式值就会报错

⑤ 隐式类

Scala2.10 后提供了隐式类,可以使用 implicit 声明类,隐式类的非常强大,同样可以扩展类的功能,比前面使用隐式转换丰富类库功能更加的方便,在集合中隐式类会发挥重要的作用

示例代码

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

    // 隐式类会独立生成一个 .class 文件,还会在当前 Main 类生成一个转换函数
    implicit class Driver(oracle: Oracle) {
      def add(): Unit = {
        println("Driver add")
      }
    }
    val oracle = new Oracle
    // 实质上是调用了转换函数生成一个隐式类对象来调用 add 方法
    oracle.add() // Driver add
    oracle.func() // Oracle func
  }
}

class Oracle {
  def func(): Unit = {
    println("Oracle func")
  }
}

隐式类的特点

  1. 其所带的构造参数有且只能有一个

  2. 隐式类必须被定义在 伴生对象包对象 里,即隐式类不能是 顶级的(top-level objects)

  3. 隐式类不能是 case class(类型匹配)

  4. 作用域内不能有与之相同名称的标示符

⑥ 隐式转换时机

  1. 当方法中的参数的类型与目标类型不一致时

  2. 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换(根据类型)

隐式转换解析规则(了解)

隐式转换前提

  1. 不能存在二义性

  2. 隐式操作不能嵌套