什么是隐式转换
我理解的隐式转换是一种能像装饰器设计模式
一样,对原有功能进行增强
的语法。
当原有函数不具备某些我们想要的功能时,我们或许可以通过隐式转换来解决这样的问题。
比如我们想得到一杯果汁,却只有一个苹果的时候
-
装饰器设计模式
用一个榨汁机把苹果榨成果汁给用户。
-
隐式转换
将苹果转换成果汁给用户。
-
例一
import java.io.{File} import scala.io.Source object Test01 { implicit class RichFile(from:File){ def readAll: String = Source.fromFile(from.getPath).mkString } def main(args: Array[String]): Unit = { val file = new File("d://in/imp.txt") println(file.readAll)//file变成了RichFile } }
上面的例子对原本java的File类新增了一个readAll的方法,做到了功能的增强。
隐式转换做的事:将java的File类转换成了RichFIle类。
-
例二
import java.io.File import scala.io.Source object Test01 { implicit def file2Array(file: File):Array[String] = { Source.fromFile(file.getPath).mkString.split("\n") } def printAll(source: Array[String]) = { source.map(x=> println(x)) } def main(args: Array[String]): Unit = { printAll(new File("d://in/imp.txt")) } }
上面的例子,明明printAll需要的是一个Array[String],但是传进去的却是一个File,却同样能得到想要的结果(打印文本的内容)
隐式转换做的事:将java的File类转换成了Array[String]类。
Scala中的隐式转换是一种非常强大的代码查找机制。当函数、构造器调用缺少参数或者某一实例调用了其他类型的方法导致编译不通过时,编译器会尝试搜索一些特定的区域,尝试使编译通过。
隐式操作规则(https://www.jianshu.com/p/a344914de895)
- 标记规则:只有标记为implicit的变量,函数或对象定义才能被编译器当做隐式操作目标。
- 作用域规则:插入的隐式转换必须是单一标示符的形式处于作用域中,或与源/目标类型关联在一起。单一标示符是说当隐式转换作用时应该是这样的形式:file2Array(arg).map(fn)的形式,而不是foo.file2Array(arg).map的形式。假设file2Array函数定义在foo对象中,我们应该通过
import foo._
或者import foo.file2Array
把隐式转换导入。简单来说,隐式代码应该可以被"直接"使用,不能再依赖类路径。
假如我们把隐式转换定义在源类型或者目标类型的伴生对象内,则我们可以跳过单一标示符的规则。因为编译器在编译期间会自动搜索源类型和目标类型的伴生对象,以尝试找到合适的隐式转换。 - 无歧义规则:不能存在多于一个隐式转换使某段代码编译通过。因为这种情况下会产生迷惑,编译器不能确定到底使用哪个隐式转换。
- 单一调用规则:不会叠加(重复嵌套)使用隐式转换。一次隐式转化调用成功之后,编译器不会再去寻找其他的隐式转换。
- 显示操作优先规则:当前代码类型检查没有问题,编译器不会尝试查找隐式转换。