1.1 概述
隐式转换和隐式参数是Scala中非常有特色的功能,也是Java等其他编程语言没有的功能。我们可以很方便地利用隐式转换来丰富现有类的功能
隐式转换的本质 :隐式转换是在Scala编译器进行类型匹配时,如果找不到合适的类型,那么隐式转换会让编译器在作用范围内自动推导出来合适的类型。当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译。
1.2 分类
隐式参数
普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。
说明
(1) 同一个作用域中,相同类型的隐式值只能有一个
(2) 编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。
(3) 隐式参数优先于默认参数
案例
/*隐式参数*/
def main(args: Array[String]): Unit = {
//str为隐式值
implicit val str="scala";
printStr//结果打印helloscala
//底层是柯里化 def printStr()(implicit Str:String): Unit={
// println("hello"+Str)
//加上小括号调用也应该加上:printStr()//结果打印helloscala
implicit val num: Int = 18
// 简便写法
def printStr(): Unit = {
println("hi, " + implicitly[String])//hi, 18
}
}
//str为隐式参数
def printStr(implicit Str:String): Unit ={
println("hello"+Str)
}
}
上述案例中并没有给函数传递参数当使用隐式参数时,会在当前作用域查找对应的隐式值
隐式函数
隐式转换函数是使用关键字implicit修饰的函数。当Scala运行时,假设如果A类型变量调用了method()这个方法,发现A类型的变量没有method()方法,而B类型有此method()方法,会在作用域中寻找有没有隐式转换函数将A类型转换成B类型,如果有隐式转换函数,那么A类型就可以调用method()这个方法。
作用:隐式转换可以在不需改任何代码的情况下,扩展某个类的功能
案例
object Test02 {
class Cat(){
def miao(): Unit ={
println("i am a cat")
}
}
class Dog
implicit def dogToCat(dog:Dog): Cat ={
new Cat()
}
def main(args: Array[String]): Unit = {
new Dog().miao()//i am a cat
}
}
隐式类
使用implicit关键字修饰的类就是隐式类。若一个变量A没有某些方法或者某些变量时,而这个变量A可以调用某些方法或者某些变量时,可以定义一个隐式类,隐式类中定义这些方法或者变量,隐式类中传入A即可。
在 Scala2.10 后提供了隐式类,可以使用 implicit 声明类,隐式类的非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要的作用。
隐式类说明
(1) 其所带的构造参数有且只能有一个
(2) 隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。
案例一
object Test03 {
implicit class Dog(cat:Cat){
def bark(): Unit ={
println("旺旺!")
}
}
class Cat(){
}
def main(args: Array[String]): Unit = {
new Dog(new Cat).bark()//旺旺
}
}
案例二
object Test04 {
implicit class Dog(a:Int){
def bark(): Unit ={
println(a)
}
}
class Cat(){
}
def main(args: Array[String]): Unit = {
10.bark()//10
}
}
2.隐式解析机制
说明
(1) 首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)。( 一般是这种情况)
(2) 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生对象以及该类型所在包的包对象。