implicit關鍵字詳解


implicit

  1. implicit是scala中的一個關鍵字,下面從五個方面介紹下implicit
    1. 隱式轉換函數:implicit def int2str(x:Int):String = x.toString
    2. 隱式類:implicit class Student(x: Int) {    }
    3. 隱式參數:def Student[T](x:T,y:T)(implicit ordered: Ordering[T]):Int = ordered.read(x,y)
    4. 隱式值:implicit val x: Int = 0
    5. 隱式對象:implicit object obj {}
  2. Scala支持兩種形式的隱式:
    1. 隱式值:用於給方法提供參數(隱式轉換函數,隱式對象都可以作為隱式值為方法提供隱式參數)
    2. 隱式視圖:用於對象類型間的轉換使函數的調用能夠編譯通過(隱式轉換函數,隱式類都可以看成是隱式視圖的隱式轉換)
  3. 作用:通過隱式轉換可以極大的減少代碼量,讓編譯器去去搜索作用域內的implicit修飾信息進行隱式轉換、隱式賦值
  4. implicit修飾的都必須滿足無歧義規則
  5. 隱式轉換的存放的地點:需要導入包 :import com.bigdata.study.scala._
    1. 當前程序可見作用域
    2. 原類型的伴生對象中
    3. 其他object中

隱式轉換函數

  1. 隱式轉換函數:使用implicit關鍵字修飾的函數
  2. 隱式轉換的前提:
    1. 隱式轉換函數只接受一個參數,對於接受多參數的隱式函數來說就沒有隱式轉換的功能
      implicit def int2str(x:Int):String = x.toString // 正確
      implicit def int2str(x:Int,y:Int):String = x.toString // 錯誤
    2. 不支持嵌套的隱式轉換
      class A{
           def hi = println("hi")
          }
      
          implicit def int2str(x:Int):String = x.toString 
      
          implicit def str2A(x:Int,y:Int):A = new A
      
          "str".hi  // 正確
          1.hi      // 錯誤
    3. 不能存在二義性,即同一個作用域不能定義兩個相同類型的隱式轉換函數(即是不能存在兩個都是將類型a轉換成類型b的函數)
      implicit def int2str(x:Int):String = x.toString 
      implicit def anotherInt2str(x:Int):A = x.toString
    4. 代碼能夠在不使用隱式轉換的前提下能編譯通過,就不會進行隱式轉換(即當表達式在編譯不通過的情況下才會調用隱式轉換,如果編譯通過就不調用)
  3. 一個對象調用一個函數編譯不通過只有兩個原因:a.fun(b) 
    1. 當方法中的參數的類型b與目標類型不一致時
    2. 當對象a調用類中不存在的方法或成員時
  4. 隱式轉換的順序:隱式轉換使表達式通過編譯的順序是 b到a.(先對b進行轉換看是否通過,如果不通過在對a進行轉換,如果都轉換之后還不通過就報錯)
  5. 隱式轉換的作用:
    1. 編譯器會在當前作用域尋找合適的隱式轉換使將a或者對象b進行轉換類型使編譯通過
    2. 就是擴展已有的類,在不修改原有類的基礎上為其添加新的方法、成員(把一種類型自動轉換成另外一種類型,進而使用另外一種類型中的屬性和方法)

  例子:

object ImplicitDemo {
    // TODO:定義隱式轉換函數,地點一 -> 當前程序可見作用域
    implicit def man2SuperMan(man: Man): SuperMan = new SuperMan(man.name)
    def main(args: Array[String]): Unit = {
        // 平時的時候,普通人, 該上學的上學
        val man = new Man("super")
        // 怪獸出現,毀滅人類,普通人變身奧特曼,吊打怪獸
        import com.erongda.bigdata.scala.oop.demo07.AA._
        man.emitLaser()
    }
}

隱式類

  1. Scala2.10引入了一種叫做隱式類的新特性。隱式類指的是用implicit關鍵字修飾的類。在對應的作用域內,帶有這個關鍵字的類的主構造函數可用於隱式轉換。
  2. 限制條件:
    1. 只能在別的trait/類/對象內部定義。
      object Test {implicit class person(x: Int)} // 正確! 
      implicit class person(x: Double) // 錯誤!
    2. 構造函數只能攜帶一個非隱式參數(雖然我們可以創建帶有多個非隱式參數的隱式類,但這些類無法用於隱式轉換。)
       implicit class Test(str: String) // 正確!
       implicit class Test[T](str: String, index: Int) // 錯誤!
       implicit class Test[T](str: String)(implicit index: Index) // 正確!
    3. 在同一作用域內,不能有任何方法、成員或對象與隱式類同名。(注意:這意味着隱式類不能是case class。)
      object Test{
        def main(args: Array[String]): Unit = {
          implicit class Test(x: Int) // 錯誤!
          val x = 1
          implicit class x(y: Int) // 錯誤!
          implicit case class Baz(x: Int) // 錯誤!
        }
      }
  3. 隱式類和隱式轉換函數區別:都是實現隱式轉換,各有優點(比如:a想添加b方法)
    1. 隱式轉換函數:首先創建一個有b方法的類c ,在寫一個隱式轉換函數fun(a)將對象a變成對象c
    2. 隱式類:構造一個隱式類c(a),將參數a的類型轉換成自己的類型c,直接調用b方法 
    3. 優缺點:隱式類比隱式轉換函數更加簡單,但是隱式轉換函數的功能更加強大,因為需要多個對象object1,object2,object3添加方法,隱式類需要為每一個對象創建一個隱式類(方法),隱式轉換函數只需要創建一個對象(方法),為每個object1,object2,object3添加一個隱式轉換函數即可

 

object ImplicitTest {
  class  Man{}
  //隱式類
implicit  class Teacher(man: Man){
  def fly: Unit = {
    println("在教書")
  }
}
  //隱式轉換函數
  class Student(man:Man){
    def study: Unit ={
      println("在學習")
    }
  }
implicit def ManToStudent(man:Man)=new Student(man)
  def main(args: Array[String]): Unit = {
    val man = new Man
    man.fly
    man.study
  }
}

 

隱式參數

  1. 隱式參數:使用關鍵字implicit進行標識參數就是隱式參數,隱式參數一般和普通的參數放在兩個不同的括號中(def student(name:String)(implicit age:Int))
  2. 函數的調用:在調用含有隱式參數的函數時可以不用傳遞隱式參數,編譯器會自動尋找合適的隱式值當做隱式參數,而只有用implict標記過的值、對象、函數才能被找到。
  3. 隱式參數有默認值,可以用賦值,也可以當做一個普通的參數那樣進行賦值

尋找隱式值

object ImplicitTest {
  def main(args: Array[String]): Unit = {
    implicit val ages = 12
    def student(name:String)(implicit age:Int): Unit ={
      println(s"$name 今年 $age 歲了")
    }
    student("Tom")
    student("Tom")(15)
  }
}

尋找隱式對象和隱式函數

object ImplicitTest {
  def main(args: Array[String]): Unit = {
//    例如自動尋找隱式對象:
    implicit object Student {
      def Study(s:String) = println(s"好好學習 $s!")
    }
    def test(s:String)(implicit stu: Student.type ) = {
      stu.Study(s)
    }
    test("Tom")   //
//    自動尋找隱式函數:
    implicit def int2str(x: Int): String = x.toString

    def test1(x: Int, fun: String => Unit)
             (implicit age: Int => String) = {
      fun(age(x))
    }
    test1(12, println) // 打印出"12"
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM