《scala for the impatient》 隐式转换和隐式参数
所谓隐式转换(implicit conversion function)是以implicit声明的带有单个参数的函数。
它会自动应用,将值从一个类型转到另一种类型。
隐式转化函数可以是任何名称,不需要被显示调用。
1.利用隐式转化丰富现有类库的功能
在scala中可以基于原类型自定义一个经过装饰过丰富过的类型
//为java.io.File 类增加一个read方法 class RichFile(val from: java.io.File) { def read = Source.fromFile(from.getPath).mkString }
然后提供一个隐式转化类将原来的类型转换到新类型
implicit def file2RichFile(from: java.io.File) = new RichFile(from)
测试
package test.scala.lang.implicit_ import scala.io.Source import test.scala.lang.implicit_.RichFile._ //为java.io.File 类增加一个read方法 class RichFile(val from: java.io.File) { def read = Source.fromFile(from.getPath).mkString } object RichFile{ implicit def file2RichFile(from: java.io.File) = new RichFile(from) } object TestImplicit { def main(args: Array[String]): Unit = { test } def test = { val file = new java.io.File("src/main/resources/log4j.properties") println(file.read) } }
2.引入隐式转换
scala会考虑如下的隐式转换函数:
- 位于原类型或目标类型的伴生对象中的隐式函数
- 位于当前作用域可以以 单个标识符 指代的隐式函数
比如上面的
implicit def file2RichFile(from: java.io.File) = new RichFile(from)
位于RichFile的伴生对象中。
在import的时候
不是import test.scala.lang.implicit_.RichFile,这样引入的是伴生对象本身,read方法不能 以单个标识符调用,需要带上类型名称,RichFile.read;
在REPL中,可以通过:implicits 来查看所有除Predef外被引入的隐式成员.
引入隐式转换的 尽量使用局部化的方式,也可以引入单个隐式转换
import test.scala.lang.implicit_.RichFile.file2RichFile
3.隐式转换规则
隐式转换在以下三种情况下会被考虑
- 当表达式的类型与预期的类型不同时
- 当对象访问一个不存在的成员时
- 当对象调用某个方法,而该方法的参数声明与传入参数不匹配时
以下三种情况编译器不会尝试使用隐式转换:
- 如果不使用隐式转换即可通过编译,则不使用隐式转换;
- 编译器不会尝试同时执行多个隐式转换;
- 存在二义性的转换是个错误,编译器将会报错;
编译时使用参数
scalac -Xprint:typer ....
可以看到加入隐式转换后的代码。