Scala隐式转换

什么叫做隐式转换

隐式转换函数是以implicit关键字声明的带有单个参数的函数。这种函数将会自动应用,将值从一种类型转换为另一种类型;在代码重构设计上,可以避免冗余的代码,使得代码非常优雅。

例子1

import java.io.File
import scala.io.Source
/**
  * 隐式转换 进来一个普通的出去一个加强的
  */
object Context {
  implicit def fileToRichFile(file:File) = new RichFile(file)
}
class RichFile(file:File){
  def read():String = Source.fromFile(file).mkString
}
object implicitValue {
  def main(args: Array[String]): Unit = {
    val file = new File("D:/ssc/wc/1.txt")
    import Context.fileToRichFile
    val value = file.read()
    println(value)
  }
}

隐式转换的时机:

  1. 当方法中的参数的类型与目标类型不一致时。
  2. 当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换。
  3. 当对象调用类的方法想被隐式转换成自己想要转换的方法。即上面这种情况。

所以上述总结是隐式转换的时机是在方法被使用之前

使用场景

隐式参数

object ImplicitParam {
  def main(args: Array[String]): Unit = {
    implicit val name = "tony"
    sayHello(25)
  }
  def sayHello(age:Int)(implicit name:String)
            = println("my name is "+ name + "my age is " + age)
}

sayHello函数有两个参数,其中name为隐式参数,在实际调用中不需要显示传入这个参数,但是在作用域范围内必须声明一个String类型的隐式变量,这样在调用的时候,会自动传入这个变量。注意:如果在同一个作用域内定义了两个同类型的隐式变量,则会有冲突。
在这里插入图片描述

类型匹配

object ImplicitType {
  def main(args: Array[String]): Unit = {
    implicit def int2Range(num: Int): Range = 1 to num
    val str = spreadNum(5)
    println(str)
  }
  def spreadNum(range: Range) : String = range.mkString(",")
}

上面所示,spreadNum函数签名是个Range类型的参数,但是传入的值是一个Int类型的,所以编译器在作用域内找到了int2Range隐式转换函数,自动将int转换为range对象来适配

类型增强

object ImplicitEnType {
  def main(args: Array[String]): Unit = {
    implicit def man2SuperMan(man:Man) = new SuperMan(man.name)
    val fei = new Man("fei")
    fei.fly
  }
}
class Man(val name:String)

class SuperMan(val name:String){
    def fly = println(name + " can fly")
}

编译器在调用fly方法时,发现Man对象并没有这个函数,然后通过man2SuperMan隐式函数转换成SuperMan对象,进而调用他的fly函数,来实现类型增强功能。

比较器

Ordered和Ordering

Ordered:

class Girl(val name:String,val faceValue:Int,val age:Int){}
  1. 默认有序,自定义的类继承Ordered接口,在里面重写Compare方法,和Comparable相似
  2. 通过隐式转换和示图界定
/**
  * 视图界定,隐式函数
  * viewBound 必须传进一个隐式转换的函数
  */
class MissLeft[T <% Ordered[T]] {
  def choose(first:T,sec:T):T ={
    if(first > sec) first else sec
  }
}
object Context {
  /**
    * 两种写法 选一种就行
    */
  implicit def girl2Ordered(g:Girl) = new Ordered[Girl]{
    override def compare(that: Girl): Int = {
      g.faceValue - that.faceValue
    }
  }

  implicit val girl2Ordered = (g:Girl) =>  new Ordered[Girl]{
    override def compare(that: Girl): Int = {
      g.faceValue - that.faceValue
    }
  }
}
object MissLeft {
  def main(args: Array[String]): Unit = {
    import Context._
    /**
      * Girl <% 表明Girl类的上届是Ordered,
      * 即泛型的类型必须是“某种类型”或某种类型的子类
      */
    val mL = new MissLeft[Girl]
    val g1 = new Girl("林青霞", 97, 29)
    val g2 = new Girl("王祖贤", 89, 20)
    println(mL.choose(g1, g2).name)
  }
}

把隐式转换写到类的前面的原因是,再加载类的时候加载方法,需要把方法进行隐式转换,而不是调用方法时候在进行转换。否则加载不到Ordered[Girl]方法而无法进行比较。
Ordered的隐式转换:源码

object Ordered {
  /** Lens from `Ordering[T]` to `Ordered[T]` */
  implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] =
    new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) }
}
  1. 通过上下文界定
/**
  * 上下文界定
  * 必须传进一个隐式转换的值
  */
class MissRight[T:Ordering] {
  def choose(first:T,sec:T) : T ={
    /**
      * 隐式参数
      */
    val ord = implicitly[Ordering[T]]
    if(ord.gt(first,sec)) first else sec
  }
}

object Bound{
  /**
    * 两种写法选择一种
    */
  /*implicit val girl2Ordering = new Ordering[Girl] {
    override def compare(x: Girl, y: Girl): Int = {
      x.faceValue - y.faceValue
    }
  }*/

  trait girl2Ordering extends Ordering[Girl] {
    override def compare(x:Girl,y:Girl) : Int = {
      x.faceValue - y.faceValue
    }
  }

  implicit object Girl extends girl2Ordering
}

object MissRight {
  def main(args: Array[String]): Unit = {
    import Bound._
    val mL = new MissLeft[Girl]
    val g1 = new Girl("林青霞", 97, 29)
    val g2 = new Girl("王祖贤", 89, 20)
    println(mL.choose(g1, g2).name)
  }
}

Ordering:源码

 def apply[T](implicit ord: Ordering[T]) = ord

比较器直接隐式转换

//视图界定 隐式函数
  def choose1(first: T, second: T)(implicit ord: T => Ordered[T]): T = {
    if (first > second) first else second
  }

  //上下文界定,隐式值
  def choose2(first: T, second: T)(implicit ord: Ordering[T]): T = {
    if (ord.gt(first, second)) first else second
  }

  def choose3(first: T, second: T)(implicit ord: Ordering[T]): T = {
    import Ordered.orderingToOrdered
    if (first > second) first else second
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值