隐式(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")
}
}