1.什么是隐式转换
我们经常引入第三方库,但当我们想要扩展新功能的时候通常是很不方便的,因为我们不能直接修改其代码。scala提供了隐式转换机制和隐式参数帮我们解决诸如这样的问题。
Scala中的隐式转换是一种非常强大的代码查找机制。当函数、构造器调用缺少参数或者某一实例调用了其他类型的方法导致编译不通过时,编译器会尝试搜索一些特定的区域,尝试使编译通过。
2.常用方法:
转换类型为期望的类型
当我们尝试把一个带有精度的数字复制给Int类型时,编译器会给出编译错误,因为类型不匹配。当我们创建了一个double to int的隐式转换之后编译正常通过。
还有一种情况是与新类型的操作:
case class Rational(n: Int, d: Int) {
def +(r: Rational) = Rational(n + r.n, d + r.d)
}
implicit def int2Rational(v: Int) = Rational(v, 1)
Rational(1, 1) + Rational(1, 1)//可行
1 + Rational(1, 1)//可行,隐式转换,调用int2Rational
隐式类
目前,一般不推荐 implicit def
的方式,而推荐用隐式类的方法,如下:
implicit class Calc(x:Int){
def add(a:Int):Int = a +x
}
println(1.add(2))//1自动实例化为Calc的类型
隐式视图
隐式视图:把一种类型转换为其他的类型,转换后的新类型称为视图类型。隐式视图会用于以下两种场景:
当传递给函数的参数与函数声明的类型不匹配时
当调用foo.bar,且foo中并没有bar函数(或成员)时(常用于丰富已有的类库):
class Strings(str: String) {
def compress = str.filter(_ != ' ').mkString("")
}
implicit def strings(str: String): Strings = new Strings(str)
" a b c d ".compress//本身String格式没有compress函数,但是此处可用饮食转换将String转为自己造的Strings
另外还有类型类和模拟新语法等功能可见Scala隐式转换
另:隐式操作规则
- 标记规则:只有标记为implicit的变量,函数或对象定义才能被编译器当做隐式操作目标。
- 作用域规则:插入的隐式转换必须是
单一标示符
的形式处于作用域中,或与源/目标类型关联在一起。
单一标示符是说当隐式转换作用时应该是这样的形式:file2Array(arg).map(fn)的形式,而不是foo.file2Array(arg).map的形式。
假设file2Array函数定义在foo对象中,我们应该通过
import foo._
或者import foo.file2Array
把隐式转换导入。简单来说,隐式代码应该可以被”直接”使用,不能再依赖类路径。假如我们把隐式转换定义在源类型或者目标类型的伴生对象内,则我们可以跳过单一标示符的规则。因为编译器在编译期间会自动搜索源类型和目标类型的伴生对象,以尝试找到合适的隐式转换。
- 无歧义规则:不能存在多于一个隐式转换使某段代码编译通过。因为这种情况下会产生迷惑,编译器不能确定到底使用哪个隐式转换。