- 隐式转换是以implicit关键字声明的带有单个参数的方法,该方法是被自动调用的,用来实现自动将某种数据转换为另一种类型数据
当编译器第一次编译失败的时候,会在当前环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译 ```scala object Test { def mian(args: Array[String]): Unit = { // 正常情况 val new12 = new MyRichInt(12) println(new12.myMax(15))
// 1. 隐式函数 implicit def convert(num: Int): MyRichInt = new MyRichInt(num) // 当调用时,12没有myMax方法,就会去找将Int类型转换的方法,发现可以转换成MyRichInt,并可以调用myMax方法 // 写在隐式方法上面就找不到报错 println(12.myMax(15))
// 2. 隐式类 // 所携带的构造参数必须只有一个 // 隐式类被定义在类、伴生对象、或包对象里,不能是顶级的类 // 相当于Int类型参数拥有下面作用域中的所有方法 implicit class MyRichInt2(val self: Int) {
// 自定义比较大小的方法
def myMax2(n: Int): Int = if ( n < self) self else n
def myMin2(n: Int): Int = if (n<self) n else self
} // 调用 println(12.myMin2(15))
//3. 隐式参数 // 同一个作用域隐式参数只能有一个 implicit val str: String = “alice” // 关键字声明为隐式的时候,调用时如果不传它,就会在相应的作用域里找符合条件的隐式值 // 隐式参数优先于默认参数 // 可以定义一次参数str,在多个函数里调用 def sayHello()(implicit name: String = “tom”): Unit = { // 找的不是参数名,而是String类型的隐式值
println("hello, " + name)
} def sayHi(implicit name: String): Unit = { // 找的不是参数名,而是String类型的隐式值
println("hello, " + name)
} sayHello() // alice 会找到作用域里的隐式值str sayHi //如果函数定义时省略小括号,这里也不能写括号
// 简便写法 implicit val num: Int = 18 def hiAge(): Unit = {
println("hi, " + implicitly[Int]) // 内联函数,直接指明了调用的是隐式值
} }
// 自定义类 class MyRichInt(val self: Int) { // 自定义比较大小的方法 def myMax(n: Int): Int = if ( n < self) self else n def myMin(n: Int): Int = if (n<self) n else self }
**解析机制:**
1. 会首先在当前代码作用域下查找隐式实体(隐式方法、类、对象)
1. 第一条失败,会继续在隐式参数的类型的作用域里查找(该类型相关联的全部伴生对象及所在包对象)
<a name="HOS6A"></a>
### 示例一:手动导入隐式转换方法
```scala
// 通过隐式转换,让File类的对象具备read功能,实现将文本内容以字符串形式读取
// 将数据读到字符串
class RichFile (file: File) {
def read() = Source.fromFile(file).mkString
}
//单例对象,其中有一个隐式转换方法
object ImplicitDemo {
implicit def file2RichFile(file: File) = new RichFile(file)
}
def main(args: Array[String]): Unit = {
import ImplicitDemo.file2RichFile
val file = new File("./data/1.txt")
println(file.read())
}
执行流程:
1.先找File有没有read()方法
2.没有就去查看有没有隐式转换,将该对象转换为其它类型对象
3. 如果没有隐式转换,报错
4.如果可以将该类型对象升级为其它类型对象,则查看升级后的对象中有没有指定方法,没有就报错
- 当对象调用类中不存在的方法或者成员时,编译器会自动进行隐式转换
- 当方法中的参数类型与目标类型不一致时,编译器也会自动调用隐式转换
在当前作用域中有隐式转换方法,会自动导入隐式转换
class RichFile(file: File) {
def read() = Source.fromFile(file).mkString
}
def main(args: Array[String]): Unit = {
// 定义一个隐式转换方法
implicit def file2RichFile(file:File) = new RichFile(file)
val file = new File("./data/1.txt")
println(file.read())
}
隐式参数
Scala方法中,可以标记一个implicit的参数列表,调用该方法时,次参数列表可以不用给初始值,因为编译器会自动查找缺省值,提供给该方法
def show(name: String)(implicit delimit:(String, String)) = delimit._1 + name + delimit._2
object ImplicitParm {
implicit val delimit_default = "<<<" -> ">>>"
}
def main(args: Array[String]): Unit = {
import ImplicitParm.delimit_default
println(show("zhangsan"))
println(show("lisi")("((","))"))
}
案例:获取元素平均值
class RichList(list: List[Int]) {
def avg() = {
if(list.size == 0) None
else Some(list.sum / list.size)
}
}
def main(args: Array[String]): Unit = {
implicit def list2RichList(list:List[Int]) = new RichList(list)
val list = List(1, 2, 3, 4, 5)
println(list.avg())
}