Scala學習筆記——implicit隱式

隱式參數

 簡單隱式參數實現如下:implicit隱式傳入參數

  def calcTa2(a: Int)(implicit b: Int): Float = a*b
  implicit val t = 3
  println(calcTa2(10))

隱式轉換函數

對double值進行隱式轉換

object ImplicitTest extends App {
  implicit def double2int(d: Double) = d.toInt
  val x: Int = 3.5
  println(x)
}

隱式調用函數

object ImplicitApp extends App {

  object SimpleSateSalesTax {
    implicit val rate: Float = 0.5F
  }

  def calcTax(amount: Float)(implicit rate: Float): Float = amount * rate
  case class ComplicatedSalesTaxData(baseRate: Float, isTaxHoliday:Boolean, storeId:Int)

  object ComplicatedSalesTax {
    private def extraTaxRateForStore(id :Int) : Float = {
      val d = id match {
        case 1 => 0.2F
        case 2 => 0.8F
      }
      d
    }

    implicit def rate(implicit cstd: ComplicatedSalesTaxData) : Float =
      if(cstd.isTaxHoliday) 0.0f
      else cstd.baseRate + extraTaxRateForStore(cstd.storeId)
  }

  {
    import SimpleSateSalesTax.rate
    val amount = 100F
    println(s"Tax on $amount = ${calcTax(amount)}")
  }

  {
    import ComplicatedSalesTax.rate
    implicit val myStore = ComplicatedSalesTaxData(0.06F, false, 2)
    val amount = 100F
    println(s"Tax on $amount = ${calcTax(amount)}")
  }


  /**
    * 簡單隱式參數
    * @param a
    * @param b
    * @return
    */

  def calcTa2(a: Int)(implicit b: Int): Float = a*b
  implicit val t = 3
  println(calcTa2(10))
}

隱式轉換的時機:

  1. 當方法中的參數的類型與目標類型不一致時
  2. 當對象調用類中不存在的方法或成員時,編譯器會自動將對象進行隱式轉換

隱式解析機制

 即編譯器是如何查找到缺失信息的,解析具有以下兩種規則:

  1. 首先會在當前代碼作用域下查找隱式實體(隱式方法 隱式類 隱式對象)
  2. 如果第一條規則查找隱式實體失敗,會繼續在隱式參數的類型的作用域裏查找
    類型的作用域是指與該類型相關聯的全部伴生模塊,一個隱式實體的類型T它的查找範圍如下:
    •  如果T被定義爲T with A with B with C,那麼A,B,C都是T的部分,在T的隱式解析過程中,它們的伴生對象都會被搜索;
    •  如果T是參數化類型,那麼類型參數和與類型參數相關聯的部分都算作T的部分,比如List[String]的隱式搜索會搜索List的;
      伴生對象和String的伴生對象;
    •  如果T是一個單例類型p.T,即T是屬於某個p對象內,那麼這個p對象也會被搜索;
    •  如果T是個類型注入S#T,那麼S和T都會被搜索;
隱式參數所遵循的規則
  • 只有最後一個參數列表中允許出現隱式參數,這也適用用於只有一個參數列表的情況。
  • implicit關鍵字必須出現在參數列表的最左邊,而且只能出現一次。列表中出現在implicit關鍵字之後的參數都不是“非隱式”的。
  • 假如參數列表以implicit關鍵字開頭,那麼所有的參數都是隱式的。
“<:” 和 “>:” 和 “”作用及用法
object BorderApp extends App {

  def test[T](i: T)(implicit ev: T <:< java.io.Serializable) {
    println("OK")
  }

  test("22")
}
隱式與類型推導 <:與<:<的差異
scala> def foo[A, B <: A](a: A, b: B) = (a,b)
foo: [A, B <: A](a: A, b: B)(A, B)

scala>  foo(1, List(1,2,3))
res0: (Any, List[Int]) = (1,List(1, 2, 3))

 傳入第一個參數是Int類型,第二個參數是List[Int],顯然這不符合B <: A 的約束,編譯器在做類型推導的時候,爲了滿足這個約束,會繼續向上尋找父類型來匹配是否滿足,於是在第一個參數被推導爲Any類型的情況下,List[Int] 符合Any的子類型。

scala> def bar[A,B](a: A, b: B)(implicit ev: B <:< A) = (a,b)
bar: [A, B](a: A, b: B)(implicit ev: B <:< A)(A, B)

scala> bar(1,List(1,2,3))
<console>:13: error: Cannot prove that List[Int] <:< Int.
       bar(1,List(1,2,3))
          ^

通過隱式參數ev來證明類型時,類型推斷過程不會像上面那樣再向上尋找可能滿足的情況,而直接報錯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章