当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译,而这些方法就是隐式转换,Scala编译器所做的事情要比Java编译器做的事情要多的多
通过隐式转换,程序员可以在编写Scala程序就可以省去一部分复杂重复的代码,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码。
说明
隐式转换可以在不需改任何代码的情况下,扩展某个类的功能。
案例实操
需求:通过隐式转化为 Int 类型增加方法。
class MyRichInt(val self: Int) {
def myMax(i: Int): Int = {
if (self < i) i else self
}
def myMin(i: Int): Int = {
if (self < i) self else i
}
}
object TestImplicitFunction {
// 使用 implicit 关键字声明的函数称之为隐式函数
implicit def convert(arg: Int): MyRichInt = {
new MyRichInt(arg)
}
def main(args: Array[String]): Unit = {
// 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范围内查找能调用对应功能的转换规则,这个调用过程是由编译器完成的,所以称之为隐式转换。也称之为自动转换
println(2.myMax(6))
}
}
普通方法或者函数中的参数可以通过 implicit
关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。
按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关
object TestImplicitParameter {
implicit val str: String = "hello world!"
def hello(implicit arg: String="good bey world!"): Unit = {
println(arg)
}
def main(args: Array[String]): Unit = {
hello
hello(123)
}
}
控制台打印
hello world!
123
在 Scala2.10 后提供了隐式类,可以使用 implicit
声明类,隐式类的非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要的作用。
object TestImplicitClass {
implicit class MyRichInt(arg: Int) {
def myMax(i: Int): Int = {
if (arg < i) i else arg
}
def myMin(i: Int) = {
if (arg < i) arg else i
}
}
def main(args: Array[String]): Unit = {
println(1.myMax(3))
}
}
1里面是没有myMax(3)这个方法的,因此编译器就会找到隐式类的MyRichInt( )然后调用隐式类里面的方法
package com.atguigu.chapter10
import com.atguigu.chapter10.Scala05_Transform4.Teacher
// 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。
// 类型的作用域是指与该类型相关联的全部伴生模块,
object TestTransform extends PersonTrait {
def main(args: Array[String]): Unit = {
//(1)首先会在当前代码作用域下查找隐式实体
val teacher = new Teacher()
teacher.eat()
teacher.say()
}
class Teacher {
def eat(): Unit = {
println("eat...")
}
}
}
trait PersonTrait {
}
object PersonTrait {
// 隐式类 : 类型 1 => 类型 2
implicit class Person5(user:Teacher) {
def say(): Unit = {
println("say...")
}
}
}