天天看點

Scala隐式轉換執行個體

//[T: Ordering]:說明存在一個隐式類型Ordering[T]
class Pair_Implicits[T: Ordering](val first: T, val second: T) {
  //聲明一個隐式類型對象傳入函數
  def bigger(implicit ordered: Ordering[T]): T = {
    if (ordered.compare(first, second) > 0) first else second
  }
}

//簡化上面的寫法
class Pair_Implicitly[T: Ordering](val first: T, val second: T) {
  def bigger: T =
    if (implicitly[Ordering[T]].compare(first, second) > 0) first else second
}

//進一步簡化
class Pair_Implicitly_Ordered[T: Ordering](val first: T, val second: T) {
  def bigger: T = {
    import Ordered._
    if (first > second) first else second
  }
}

//視圖界定寫法
class Pair_Implicitly_Ordered_View_Bounds[T <% Ordered[T]](val first: T, val second: T) {
  def bigger = {
    if (first > second) first else second
  }
}

//隐式參數與隐式轉換
class Pair_Implicitly_With_Implicit_Parameters {
  def bigger[T](a: T, b: T)(implicit ordered: T => Ordered[T]): T = {
    if (a > b) a else b
  }
}

class Boy(val name: String) {
  override def toString: String = name
}

class RichBoy(val boy: Boy) {
  def upper: String = boy.name.toUpperCase
}

//通過伴生對象進行隐式轉換
class Implicits_Boy(name: String) extends Boy(name)

object Implicits_Boy {
  implicit def boy2RichBoy(boy: Boy): RichBoy = new RichBoy(boy)
}

abstract class Template[T] {
  def add(x: T, y: T): T
}

abstract class SubTemplate[T] extends Template[T] {
  def unit: T
}

object Context_Bounds_Internals {
  //下面這兩個隐式導入二選一都生效,因為Ordered與Ordering内部定義了互相轉換的隐式導入方法
  //若同時在,根據導入路徑短的有限,boy2Ordered對前三個類生效,boy2Ordering對後兩個類生效
  implicit def boy2Ordered(boy: Boy): Ordered[Boy] = (that: Boy) => -boy.name.compareTo(that.name)

  implicit val boy2Ordering: Ordering[Boy] = (x: Boy, y: Boy) => x.name.compareTo(y.name)

  //隐式類
  //有時候進行代碼重構,要增強他的某項功能同時又不想做太大的改動
  //更多用的是隐式轉換,隐式類用的不多
  implicit class EnhanceBoy(boy: Boy) {
    def getName: String = boy.name
  }

  //定義隐式對象  定義方式:implicit object XXX
  implicit object IntAdd extends SubTemplate[Int] {
    def add(x: Int, y: Int): Int = x + y

    def unit: Int = 0
  }

  implicit object StringAdd extends SubTemplate[String] {
    def add(x: String, y: String): String = x concat y

    def unit: String = ""
  }

  def main(args: Array[String]): Unit = {
    //上下文界定中的隐式參數
    //在每次上下文運作的執行個體對象中将具體的值注入到隐式參數中,而且注入的過程是自動的
    println(new Pair_Implicits(new Boy("a"), new Boy("b")).bigger)
    println(new Pair_Implicitly(new Boy("a"), new Boy("b")).bigger)
    println(new Pair_Implicitly_Ordered(new Boy("a"), new Boy("b")).bigger)
    println(new Pair_Implicitly_Ordered_View_Bounds(new Boy("a"), new Boy("b")).bigger)

    println(new Pair_Implicitly_With_Implicit_Parameters().bigger(new Boy("a"), new Boy("b")))

    /**
      * Boy對象中并沒有getName方法 編譯器會在全局範圍内查詢比對的隐式類
      * 在Context_Bounds_Internals導入的類中有EnhanceBoy接受Boy類型的類 會自動比對 、
      * 使得Boy對象通過這種隐式的方法具有getName方法
      */
    println(new Boy("zhangsan").getName)

    /**
      * 這裡沒有導入隐式對象
      *
      * 通過給Implicits_Boy類 建構一個伴生對象 在伴生對象内部定義一個隐式轉換的方法
      *
      * 執行順序:
      * 1.搜尋Implicits_Boy有無upper方法
      * 2.在上下文上搜尋(有無導入的隐式對象)
      * 3.搜尋Implicits_Boy的伴生對象内有無隐式轉換  發現implicit關鍵 嘗試比對類型
      * 例如這裡比對boy2RichBoy(boy: Boy) 傳回類型為RichBoy 在RichBoy中發現upper方法
      */
    println(new Implicits_Boy("i am Implicits_Boy").upper)

    //implicit m: SubTemplate[T]中 m是一個隐式對象就是實際在運作的對象
    def sum[T](xs: List[T])(implicit m: SubTemplate[T]): T =
      if (xs.isEmpty) m.unit
      else m.add(xs.head, sum(xs.tail))

    println(sum(List(1, 2, 3))) //6
    println(sum(List("Scala", "Spark", "Kafka"))) //ScalaSparkKafka
  }
}
           

輸出:

b
b
b
a
a
zhangsan
I AM IMPLICITS_BOY
6
ScalaSparkKafka