• 隐式转换是以implicit关键字声明的带有单个参数的方法,该方法是被自动调用的,用来实现自动将某种数据转换为另一种类型数据
  • 当编译器第一次编译失败的时候,会在当前环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译 ```scala object Test { def mian(args: Array[String]): Unit = { // 正常情况 val new12 = new MyRichInt(12) println(new12.myMax(15))

    // 1. 隐式函数 implicit def convert(num: Int): MyRichInt = new MyRichInt(num) // 当调用时,12没有myMax方法,就会去找将Int类型转换的方法,发现可以转换成MyRichInt,并可以调用myMax方法 // 写在隐式方法上面就找不到报错 println(12.myMax(15))

    // 2. 隐式类 // 所携带的构造参数必须只有一个 // 隐式类被定义在类、伴生对象、或包对象里,不能是顶级的类 // 相当于Int类型参数拥有下面作用域中的所有方法 implicit class MyRichInt2(val self: Int) {

    1. // 自定义比较大小的方法
    2. def myMax2(n: Int): Int = if ( n < self) self else n
    3. def myMin2(n: Int): Int = if (n<self) n else self

    } // 调用 println(12.myMin2(15))

    //3. 隐式参数 // 同一个作用域隐式参数只能有一个 implicit val str: String = “alice” // 关键字声明为隐式的时候,调用时如果不传它,就会在相应的作用域里找符合条件的隐式值 // 隐式参数优先于默认参数 // 可以定义一次参数str,在多个函数里调用 def sayHello()(implicit name: String = “tom”): Unit = { // 找的不是参数名,而是String类型的隐式值

    1. println("hello, " + name)

    } def sayHi(implicit name: String): Unit = { // 找的不是参数名,而是String类型的隐式值

    1. println("hello, " + name)

    } sayHello() // alice 会找到作用域里的隐式值str sayHi //如果函数定义时省略小括号,这里也不能写括号

    // 简便写法 implicit val num: Int = 18 def hiAge(): Unit = {

    1. println("hi, " + implicitly[Int]) // 内联函数,直接指明了调用的是隐式值

    } }

// 自定义类 class MyRichInt(val self: Int) { // 自定义比较大小的方法 def myMax(n: Int): Int = if ( n < self) self else n def myMin(n: Int): Int = if (n<self) n else self }

  1. **解析机制:**
  2. 1. 会首先在当前代码作用域下查找隐式实体(隐式方法、类、对象)
  3. 1. 第一条失败,会继续在隐式参数的类型的作用域里查找(该类型相关联的全部伴生对象及所在包对象)
  4. <a name="HOS6A"></a>
  5. ### 示例一:手动导入隐式转换方法
  6. ```scala
  7. // 通过隐式转换,让File类的对象具备read功能,实现将文本内容以字符串形式读取
  8. // 将数据读到字符串
  9. class RichFile (file: File) {
  10. def read() = Source.fromFile(file).mkString
  11. }
  12. //单例对象,其中有一个隐式转换方法
  13. object ImplicitDemo {
  14. implicit def file2RichFile(file: File) = new RichFile(file)
  15. }
  16. def main(args: Array[String]): Unit = {
  17. import ImplicitDemo.file2RichFile
  18. val file = new File("./data/1.txt")
  19. println(file.read())
  20. }
  21. 执行流程:
  22. 1.先找File有没有read()方法
  23. 2.没有就去查看有没有隐式转换,将该对象转换为其它类型对象
  24. 3. 如果没有隐式转换,报错
  25. 4.如果可以将该类型对象升级为其它类型对象,则查看升级后的对象中有没有指定方法,没有就报错
  • 当对象调用类中不存在的方法或者成员时,编译器会自动进行隐式转换
  • 当方法中的参数类型与目标类型不一致时,编译器也会自动调用隐式转换

在当前作用域中有隐式转换方法,会自动导入隐式转换

  1. class RichFile(file: File) {
  2. def read() = Source.fromFile(file).mkString
  3. }
  4. def main(args: Array[String]): Unit = {
  5. // 定义一个隐式转换方法
  6. implicit def file2RichFile(file:File) = new RichFile(file)
  7. val file = new File("./data/1.txt")
  8. println(file.read())
  9. }

隐式参数

Scala方法中,可以标记一个implicit的参数列表,调用该方法时,次参数列表可以不用给初始值,因为编译器会自动查找缺省值,提供给该方法

  1. def show(name: String)(implicit delimit:(String, String)) = delimit._1 + name + delimit._2
  2. object ImplicitParm {
  3. implicit val delimit_default = "<<<" -> ">>>"
  4. }
  5. def main(args: Array[String]): Unit = {
  6. import ImplicitParm.delimit_default
  7. println(show("zhangsan"))
  8. println(show("lisi")("((","))"))
  9. }

案例:获取元素平均值

  1. class RichList(list: List[Int]) {
  2. def avg() = {
  3. if(list.size == 0) None
  4. else Some(list.sum / list.size)
  5. }
  6. }
  7. def main(args: Array[String]): Unit = {
  8. implicit def list2RichList(list:List[Int]) = new RichList(list)
  9. val list = List(1, 2, 3, 4, 5)
  10. println(list.avg())
  11. }