天天看点

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