Implicits work like this: if you call a method on a Scala object, and the Scala compiler does not see a definition for that method in the class definition for that object, the compiler will try to convert your object to an instance of a class that does have that method defined
隐式转换是Scala类型系统的强大特性之一,使得静态类型动态化,为现有类库添加功能。Scala的隐式转换,有三种:
- 隐式函数
- 隐式参数
- 隐式类
隐式转换的规则:
- 如果代码无需隐式转换即可通过编译,则不会引入隐式转换
- 隐式转换只会匹配一次,即隐式转换至多发生一次
- 存在二义性的隐式转换报错,
在期望隐式转换发生作用的时候,必须告诉Scala编译器,隐式转换背后起作用的实现逻辑在哪里?这个实现逻辑称为作用域或者为上下文Context
一、隐式函数
增强一个类,添加本不存在的方法,implicit作用于函数,称之为隐式函数
package spark.examples.scala
//假如Arithmetic是已有的类库中的类,仅仅提供add函数
class Arithmetic {
def add(x: Int, y: Int): Int = {
x + y
}
}
//=========================================
//下面是增强Arithmetic类,添加一个subtract方法
//=========================================
class RichArithmetic(val arithmetic: Arithmetic) {
def substract(x: Int, y: Int) = {
x - y
}
}
//转换的逻辑,隐式方法
object ArithmeticToRichArithmetic {
//将Arithmetic转换为RichArithmetic
//Arithmetic对象上可以直接调用RichArithmetic定义的方法
implicit def arithmeticToRichArithmetic(arithmetic: Arithmetic) = {
new RichArithmetic(arithmetic)
}
}
object ImplicitDemo {
def main(args: Array[String]) {
import ArithmeticToRichArithmetic._ //引用方法
val a = new Arithmetic
println(a.add(11, 21))
println(a.substract(21,11)) //substract不属于Arithmetic
}
}
二、隐式参数:
package spark.examples.scala
object ObjectA {
def print(content: String)(implicit prefix : String) {
println(content + "," + prefix)
}
}
//ObjectA隐式转换的作用域
object ObjectAWrapper {
implicit val DEFAULT_OBJECT_A_STRING = "ObjectA"
}
object ImplicitArgument {
def main(args : Array[String]) {
ObjectA.print("ABC")( "DEF")
import ObjectAWrapper._ //Error: not enough argument if this line doesn't exist
//为String类型的参数隐式的提供DEFAULT_OBJECT_A_STRING值
ObjectA.print("ABC")
ObjectA.print("ABC")( "XYZ")
}
}
隐式参数的应用
如下代码出错:
class A[T] {
def min(a: T, b: T) {
if (a < b) a else b //泛型类T没有定义<方法
}
}
object ImplicitArgument {
def main(args : Array[String]) {
val a = new A[Int]();
a.min(10,11)
}
}
package spark.examples.scala
class A[T] {
//这里相当于为T指定约束,即T必须能够隐式转换到Ordered
//T能够隐式转换到Ordered,那么对类型T的变量使用<操作时,将隐式地将T转换为Ordered类型的变量,然后调用Ordered类型的<方法
//T隐式转换到Ordered,需要预先定义
def min(a: T, b: T) (implicit order: T=>Ordered[T]) = {
if (a < b) a else b
}
}
object ImplicitArgument2 {
def main(args : Array[String]) {
val a = new A[Int]();
println(a.min(10,11)) //Scala已经实现了Int到Ordered的隐式转换,否则3 < 4做不了
class B {}
/** 报错的原因是No implicit view available from B => Ordered[B].即B没有定义到Ordered的隐式转换,所以报错
val b = new A[B]() //
b.min(new B(), new B())
**/
}
}
三、隐式类
增强一个类型
隐式类约束
- 隐式类必须有一个带一个参数的主构造函数
- 必须定义在另一个class/object/trait里面(不能独立定义)
- 隐式类构造器只能带一个不是implicit修饰的参数
- 作用域中不能有与隐式类类型相同的成员变量,函数以及object名称
package spark.examples.scala
class B {
def add(x: Int, y: Int) = {
x + y
}
}
object ImplicitClassContext {
//隐式类,可以为一个类型(参数的类型)提供方法
//为主构造函数指定的类型进行增强
implicit class RichB(arg: B) {
def multiply(x: Int, y: Int) = {
x * y
}
}
}
object ImplicitClass {
def main(args: Array[String]) {
import ImplicitClassContext._
val b = new B();
println(b.multiply(3, 4))
}
}