天天看點

Scala隐式(Implicit)

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

           

繼續閱讀