隐式(implicit)
隐式的意义所在
隐式转换让代码具有简洁性,但是降低了可读性。事实上它故意省略了一些代码,让机器自我推断。
Scala在面对编译出现类型错误时,提供了一个由编译器自我修复的机制,编译器试图去寻找一个隐式implicit的转换方法,转换出正确的类型,完成编译。
简单示例
package implicit_test
object a_implicit_test {
def foo(msg: String): Unit = println(msg)
def main(args: Array[String]): Unit = {
foo(2)
}
// 提供了一个转换函数,从而使机器有了推断的依据,如果注释此代码,则foo(2)则会报错
implicit def intToString(i: Int): String = i.toString
}
隐式包含:隐式参数、隐式转换类型、隐式类
隐式参数
我们定义了一个隐式值,不论是在外部定义(default_value),还是在函数体本身参数中定义(name),隐式的值可以传参数也可以不传,在不传参数时它将使用隐式值,传了参数则使用参数。
package implicit_test
object b_implicit_test {
// 定义一个隐式值,此值在示例方法一中使用到
implicit val default_value: Int = 5
// 示例方法一
def add(x: Int)(implicit y: Int): Unit = {
println("相加值为 : " + (x + y).toString)
}
// 示例方法二
def sayHello(implicit name: String = "scala"): Unit = {
println(s"hello $name")
}
def main(args: Array[String]): Unit = {
/*
我们定义了一个隐式值,不论是在外部定义(default_value),还是在方法体本身参数中定义(name),隐式的值可以传参数也可以不传
在不传参数时它将使用隐式值,传了参数则使用参数
*/
add(10)
add(100)(20)
sayHello
sayHello("aaa")
}
}
隐式转换
当需要一种类型但是类型匹配又不对应时,编译器开始寻找上下文中的隐式转换;在如下示例中,编译器需要一个能够把double转化成int的函数或者方法;它将优先查找函数,如果没有再去找方法,没找到则会报错。
package implicit_test
object c_implicit_test {
// 定义一个隐式方法 (method)
implicit def doubleToInt1(double: Double): Int = {
println("-------调用方法doubleToInt1-------")
double.toInt
}
// 定义一个隐式函数 (funcion)
implicit val doubleToInt2 = (double: Double) => {
println("-------调用函数doubleToInt2-------")
double.toInt
}
// 本身temp值为2020.10,则该值不为int类型,所以编译器开始寻找上下文中的隐式转换,一个能够把double转化成int的函数或者方法;优先查找函数,如果没有再去找方法。
def main(args: Array[String]): Unit = {
val temp: Int = 2020.10
println(s"结果 : $temp")
}
}
隐式类
定义隐式类,只能在静态对象(Object XXX)中使用
package implicit_test
import java.io.File
import scala.io.Source
object d_implicit_test {
implicit class Read(file: File) {
def readFile: String = Source.fromFile(file).mkString
def fileIsEmpty: Boolean = Source.fromFile(file).isEmpty
def fileLineCount: Int = Source.fromFile(file).getLines().length
}
def main(args: Array[String]): Unit = {
val file = new File("E:\\Projects\\scala_test\\src\\main\\resources\\temp")
val check = file.fileIsEmpty
println(s"文件是否为空 : $check")
val lineCount = file.fileLineCount
println(s"文件行数 : $lineCount")
val content = file.readFile
println(s"读取内容\n$content")
}
}