Scala隐式转换与隐式参数

    Scala提供的隐式转换和隐式参数功能,是非常有特色的功能。是Java等编程语言所没有的功能。它允许程序员手动指定,将某种类型的对象转换为其他类型的对象,通过这些功能,可以实现非常强大,而且特殊的功能。

   Scala的隐式转换,其实最核心的就是定义隐式转换函数,即implicit conversion function定义的隐式转换函数,只要在编写的程序内引入,就会被Scala自动使用。Scala会根据隐式转换函数的签名,在程序中使用到隐式转换函数接受的参数类型定义的对象时,会自动将其传入隐式转换函数,转换为另外一种类型的对象并返回。 这就是隐式转换。

   隐式转换函数叫什么名字无所谓,因为通常不会由用户手动调用,而是由Scala进行调用,但是如果要使用隐式转换,则需要对隐式转换函数进行导入。因此通常建议将隐式转换函数名称命名为"one2one" 的形式。


// 案例: 特殊售票窗口(只接受特殊人群,比如:学生,老人等)
 class SpecialPerson(val name:String)
 class Student(val name:String)
 class Older(val name:String)

 implicit def object2Spec(obj :Object):SpecialPerson={
   if(obj.getClass== classOf[Student]){val stu=obj.asInstanceOf[Student];new SpecialPerson(stu.name)}
   else if(obj.getClass == classOf[Older]){val older=obj.asInstanceOf[Older];new SpecialPerson(older.name)}
   else  Nil
 }

 var ticketNumber =0 
 def buySpecialTicket(p:SpecialPerson)={
   tickNumber +=1
   "T-" +tickNumber
 }

代码展示如下:


事实上,存在着这样的执行过程,当我们调用 buySpecialTicket 函数时 ,若Scala检测到传入的参数不匹配,就会自动去查找有没有这样一种函数: 它接受 Older类型的参数,返回SpecialPerson类型 , 当找到的话,就会自动调用该函数,并传入Older参数,转换为 SpecialPerson类型,然后再回到buySpecialTicket  函数继续执行。

-- 2.  使用隐式转换加强现有类型

隐式转换非常强大的一个功能,就是可以在不知不觉中加强现有类型的功能。也就是说,可以为某个类定义一个加强版的类 ,并

定义互相之间的隐式转换,从而让源类在使用加强版的方法时,由Scala自动进行隐式转换为加强类,然后再调用该方法。

//案例: 超人变身
 class Man(val name:String)
 class SuperMan(val name:String){
   def emitLaser=println("emit a laster!")
 }

 implicit def man2superman(man:Man):Superman=new Superman(man.name)

 val leo = new Man("leo")
 leo.emitLaser

代码展示如下:


--  3. 隐式转换函数的作用域与导入

   Scala默认会使用两种隐式转换,一种是源类型,或者是目标类型的伴生对象内的隐式转换函数;一种是当前程序作用域内的可以用唯一标识符表示的隐式转换函数。

  如果隐式转换函数不在上述两种情况下的话,那么就必须手动使用import语法引入某个包下的隐式转换函数,比如import test._ 。 通常建议,仅仅在需要进行隐式转换的地方,比如某个函数或者方法内,用import导入隐式转换函数,这样就可以缩小隐式转换函数的作用域,避免不需要的隐式转换。

   前面几个例子都是在同一个作用域, 所以不需要进行手动导入

-- 4. 隐式转换函数的发生时机 

 1) 调用某个函数。但是给函数传入的参数类型,与函数定义的接收参数类型不匹配(比如:上面的案例 特殊售票窗口)
  2) 使用某个类型的对象,调用某个方法,而这个方法并不存在于该类型时(比如:案例: 超人变身)

  3) 使用某个类型的对象,调用某个方法,虽然该类型有这个方法,但是给方法传入的参数类型,与方法定义的接收参数的类型不匹配(案例:特殊售票窗口加强版)

  // 案例: 特殊售票窗口加强版
  class TicketHouse{
    var ticketNumber =0
    def buySpecialTicket(p :SpecialPerson)={
      ticketNumber+=1
      "T- " +ticketNumber
    }
  }

代码展示如下:


注意到: 我们调用对象中的方法时,传入的参数类型与定义时的并不匹配,所以此时Scala就自动进行了隐式转换 ,再去执行函数。

-- 5.  隐式参数

   所谓的隐式参数,指的是在函数或者方法中,定义一个用implicit修饰的参数,此时Scala会尝试找到一个指定类型的,用implicit修饰的对象,即隐式值,并注入参数。

  Scala会在两个范围内查找:

    一种是当前作用域内可见的val或var定义的隐式变量;

    一种是隐式参数类型的伴生对象内的隐式值。

//案例: 考试签到
  class SignPen{
    def write(content:String) =println(content)
  }
  implicit val signPen =new SignPen

  def signForExam(name:String)(implicit signPen:SignPen){
    signPen.write(name+" come to exam in time")
  }

  signForExam("leo")

代码展示如下:


对执行结果分析如下: signForExam函数需要一个SignPen对象,但是这个对象从哪里来呢?Scala发现,该参数是由implicit修饰的,于是就到作用域里面去查找,此时就会发现 signPen,就会把该对象注入到signForExam函数中。然后正常执行函数。


猜你喜欢

转载自blog.csdn.net/m0_37564404/article/details/80851612