这篇短文将结合实例对隐式转换的各种场景进行解释和总结,希望看完的人能够安全驶过隐式转换这个大坑。
隐式转换函数
隐式转换函数有两种作用场景。
- 1 转换为期望类型:就是指一旦编译器看到X,但需要Y,就会检查从X到Y的隐式转换函数。
- 2 转换方法的调用者:简单来说,如obj.f(),如果obj对象没有f方法,则尝试将obj转换为拥有f方法的类型。
object ImpFunction extends App {
class Dog(val name: String) {
def bark(): Unit = println(s"$name say: Wang !")
}
implicit def double2int(d: Double): Int = d.toInt
implicit def string2Dog(s: String): Dog = new Dog(s)
val f: Int = 1.1 //转换为期望类型,1.1通过double2int转成了Int类型
println(f)
"Teddy".bark() // 转换方法的调用者,字符串通过string2Dog转成了Dog, 于是有了bark方法
}
// output
// 1
// Teddy say: Wang !
val f: Int = 1.1
因为类型不匹配,这段本来是无法通过编译的,但是编译器发现存在一个Double至Int的隐式转换函数,所以进行了隐式转换。
"Teddy".bark()
String类型本来是没有bark方法的,但是编译器发现了隐式转换string2Dog可以使得String转成一种拥有bark方法的类型,相当于进行了这样的转换:string2Dog("Teddy").bark()
。
注意事项
需要注意的是,编译器只关心隐式转换函数的输入输出类型,不关心函数名,为避免歧义,同一个作用域中不能有输入输出类型相同的两个隐式转换函数,不然编译器会报错。
隐式类
Scala 2.10引入了一种叫做隐式类的新特性。隐式类指的是用implicit关键字修饰的类。使用情况与隐式转换函数类似,可以看做将类的构造函数定义为隐式转换函数,返回类型就是这个类。
package io.github.liam8.impl
object ImpClass extends App {
implicit class Dog(val name: String) {
def bark(): Unit = println(s"$name say: Wang !")
}
"Teddy".bark()
}
注意事项
这段来自官网IMPLICIT CLASSES隐式类有以下限制条件:
- 1 只能在别的trait/类/对象内部定义。
object Helpers {
implicit class RichInt(x: Int) // 正确!
}
implicit class RichDouble(x: Double) // 错误!