scala教程:隐式转换-隐式函数(implicit)

介绍

本文介绍 scala 2.10版之前的方式:隐式函数

隐式函数:用 implicit 修饰 的函数,且该函数 只有一个参数。

scala编译失败时,会在当前的环境中查找能让代码编译通过的方法,实现 二次编译,此时,这个函数会 自动调用

案例

将 浮点型数字 赋值给 Int型的 常量 或 变量,正常情况下会报错,见下面代码:

object Test {
  def main(args: Array[String]): Unit = {
    val i:Int=3.5 //此处报错,3.5浮点型,不能赋值给Int型的i
    println(i)
  }
}

可通过 隐式函数 实现 隐式转换,将 浮点型数字 转换成 整数,再赋值给 Int型的 常量 或 变量,修改如下:

object 隐式转换 {
  def main(args: Array[String]): Unit = {
    /*不需要额外处理。
    *scala编译失败时,会在当前的环境中查找能让代码编译通过的方法,实现二次编译
    */
    val i:Int=3.5
    println(i)
  }
  //隐式函数,形参为double,表示可以接受浮点型数字
  // 必须有返回值类型,否则报错
  implicit def to(a:Double):Int ={
    a.toInt //转换成整数,并返回
  }
}

或者

object 隐式转换 {
  def main(args: Array[String]): Unit = {
    //定义在 main() 方法内
    implicit def to(a:Double):Int ={
      a.toInt
    }

    val i:Int=3.5
    println(i)
  }
}

注意

  1. 隐式转换 与 隐式函数的名称 无关,与隐式函数的 形参类型 和 返回值类型 有关

  2. 当前环境中,隐式函数 可以有多个,但 只能有一个隐式函数被识别

  3. 不能嵌套使用

  4. 隐式函数 名字相同 时,形参列表必须不同

  5. 隐式函数 名字不同 时, 参数列表 或 返回值类型,必须有一个不同,否则报错

可以有 多个 隐式函数

object 隐式转换 {
  def main(args: Array[String]): Unit = {

    implicit def to(a:Double):Int ={
      a.toInt
    }
    implicit def to2(a:String):Int ={
      a.toInt
    }

    val i:Int=3.5
    val i2:Int="3"
    println(i)
  }

}

只能有一个隐式函数被识别

object 隐式转换 {
  def main(args: Array[String]): Unit = {

    implicit def to(a:Double):Int ={ 
      a.toInt
    }
    implicit def to2(a:Double):Int ={
      a.toInt
    }

    //2个隐式函数 形参类型、返回类型完全相同,不知道调用哪个,下面代码会报错(没有下面代码不会报错)
    val i:Int=3.5
  }

}

不能嵌套使用

def main(args: Array[String]): Unit = {

  implicit def to(a:Double):Int ={
    val x:Int=3.1//隐式函数还未生效,无法使用
  }
  val i:Int=3.5
}

隐式函数名字相同时,形参列表必须不同

object s37implicit {

  def main(args: Array[String]): Unit = {

    val i:Int = 3.5
    println(s"i=$i")

  }

  implicit def to(d:Double) : Int ={
    println(s"调用隐式函数,参数d=$d")
    d.toInt
  }

  implicit def to(d:Double,i:Int) : Double ={
    println(s"调用隐式函数,参数d=$d")
    d.toInt
  }

}

隐式函数 名字不同 时, 参数列表 或 返回值类型,必须有一个不同,否则报错

案例:不改源码,扩展类库功能

不改变源码的情况下,给 Student 类增加 play方法

class Student{
  def study(lession:String):Unit={
    println("学习 "+lession)
  }
}

实现

object 隐式转换_增加方法 {
  def main(args: Array[String]): Unit = {
    val std:Student = new Student()
    std.study("scala")
    // 隐式转换 ,底层实现:to(std).play("篮球")
    std.play("篮球")

  }

  implicit def to(std:Student):StudentEx={
    new StudentEx()
  }
}


class StudentEx{
  def play(str:String):Unit = {
    println("玩 "+str)
  }
}

class Student{
  def study(str:String):Unit={
    println("学 "+str)
  }
}

执行流程:


原文出处:/show_1IX1Kq9kClbG.html