2019独角兽企业重金招聘Python工程师标准>>>
1:隐式转换应用
1.1 隐式转换为期望类型
隐式转换为期望类型是编译器会使用隐式操作的第一个地方。一旦编译器看到了X,但是需要Y,就会检查从X到Y的隐式转换函数。例如:
val i : Int = 3.5
<console>:10: error: type mismatch;found : Double(3.5)required: Intval i : Int = 3.5
然而,可以通过定义隐式转换消除这个问题:
implicit def doubleToInt(x: Double) = x.toInt
scala> val i : Int = 3.5
i: Int = 3
过程如下:编译器看到了3.5 Double,但是它需要Int(此处导致类型错误),但是它搜索了从Double到Int的隐式转换,发现 doubleToInt(因为doubleToInt可以当作单一标示符处于作用域当中),实际上,代码后来变成:
val i : Int = doubleToInt(3.5)
1.2 转换接收者
隐式转换同样还应用于方法调用的接收者,也就是方法调用的对象。
a:与新类型的交互操作
接收者转换的主要用途之一是使得新类型更为平滑地集成到现存类型当中。例如,如下有个例子:
Rational 类的片段
class Rational(n:Int,d:Int){
...
def + (that:Rational):Rational = ...
def + (that:Int):Rational = ...
...
}
Rational类有两个重载的+号方法变体,分别带 Rational 以及Int为参数。可以做有理数之间的加法,以及有理数加上整数:
val oneHalf = new Rational(1,2)
oneHalf + oneHalf
oneHalf + 1
但是:1 + oneHalf 却有问题,因为Int并没有合适的加有理数的方法。
此处,我们可以定义从Int到Rational的隐式转换:
implicit def intToRational(x:Int) = new Rational(x,1)
b:模拟新的语法
隐式转换的另一种主要用途是模拟添加新的语法。
比如: Map(1-> "one",2->"two")
而 -> 只是定义在标准scala序文(scala.predef)中的类 ArrowAssoc的方法。这个序文还定义了从Any到ArrowAssoc的隐式转换。在 1-> "one" 的时候,编译器会插入从1到ArrowAssoc的转换以便找到 ->方法。以下是相关的定义:
package scala
object Predef{class ArrowAssoc[A](x:A){def -> [B](y:B):Tuple2[A,B] = Tuple2(x,y) }implicit def any2ArrowAssoc[A](x:A):ArrowAssoc[A]=new ArrowAssoc(x)....
}
2.隐式转换规则
a.标记规则:只有标记为implicit才能可用
b.做用户规则:插入的隐式转换必须以单一标识符的形式处于作用域中,或者跟转换的源或目标类型关联在一起。
例外只有一个:编译器还会在源类型活着转换的期望目标类型的伴生对象中寻找隐事定义。例如:
object Dollar{implicit def dollarToEuro(x:Dollar):Euro = ...
}
class Dollar{
}
c.无歧义规则:不存在其他可插入的转换
d:单一调用规则:只会尝试一个隐事操作
e:显式操作先行
PS:文章整理自 Programming in scala