scala的隐式转换基本使用

23 阅读4分钟

了解隐式转换的定义

隐式转换是指:scala自动把一种类型转成另一种类型的过程。这个过程对用户编程而言不可见,不需要用户手动编写代码。

隐式函数

在scala.Predef中,可以看到有系统提供了默认的情况。

隐式函数的定义:通过implicit关键字修饰的函数,它的功能是把一种类型的数据转成另一种类型。

【注意点】: (1)调用时机,在系统自动把数据从类型1隐式转为类型2时出错时,被自动调用。

(2)函数名可以自定义(一般取名为类型1to类型2),但是参数和返回值必须有限制。

package imp

  def main(args: Array[String]): Unit = {
    // 1.隐式转换
    var i:Int = 1;

    var d:Double =1.1

    d = i // 把int -> doubleleix

    d = i.toDouble
    println(s"d=${d}")

    i = d  // 存在一个隐式转换   把double -> int 报错!!!
    i = 100.1
    i = 100.1
  }

}

屏幕截图 2025-12-29 081837.png

【添加后】
package imp

// 隐式转换函数
//   1. 用关键字 implicit 修饰
//   2. 它的函数名不重要(),重要的是它的 参数和返回值的类型
//   3.系统会自动调动它

//  注意:不能写两个同类型 (参数和返回值的类型都是一样)的隐式转换函数,它会报错!!!

// 它的参数是Double,它的返回值是Int,它的作用是:当代码中出现了需要把Double转换成Int的时候,系统会自动调动它

object imp01 {

  implicit def doubleToInt(x:Double):Int = {
    println("double to int...")
    x.toInt
  }


  def main(args: Array[String]): Unit = {
    // 1.隐式转换
    var i:Int = 1;

    var d:Double =1.1

    d = i // 把int -> doubleleix

    d = i.toDouble
    println(s"d=${d}")

    i = d  // 存在一个隐式转换   把double -> int 报错!!!
    i = 100.1
    i = 100.1
  }

}

屏幕截图 2025-12-29 082432.png

【如果代码的过程中,出现了类型不一致的问题,而我们要遵守OCP开发原则,所以不去修改业务代码。此时,选择让编译器去自动查找转换操作(第一次转换失败了,第二次去找规则,所以也叫二次编译)】

隐式参数

如果一个参数的默认值会反复修改

在开发的过程中,如果知道有个参数会被改动,就可以添加implicit,但是implicit在参数列表中只能出现一次,并要写在参数列表的最前面,对所有的参数列表生效。

如果一个函数有多个参数,并且你只想对某个参数进行隐式转换,那么,可以使用柯里化的方式来定义参数,并且把转换的参数定义在参数列表的最后。

【改前】

package imp

// 在写代码的过程当中,尽量不要去修改之前的代码
// 隐式参数:
//   1.在开发过程中,如果预判一个参数将来会变动,就可以把它设置为implicit
object imp02 {

def reg(name:String,password:String="123456"):Unit = {
    println(s"您注册成功,姓名:${name},密码:${password}")
  }
  def main(args: Array[String]): Unit = {

    reg("小花")  // 没有传入密码,使用默认值123456
    reg("小白")("admin")

  }
}
【改后】
package imp

// 在写代码的过程当中,尽量不要去修改之前的代码
// 隐式参数:
//   1.在开发过程中,如果预判一个参数将来会变动,就可以把它设置为implicit
object imp02 {

  implicit val defaultpassword:String = "88888888"

  def reg(name:String)(implicit password:String="123456"):Unit = {
    println(s"您注册成功,姓名:${name},密码:${password}")
  }

//  def reg(name:String,password:String="123456"):Unit = {
//    println(s"您注册成功,姓名:${name},密码:${password}")
//  }
  def main(args: Array[String]): Unit = {

    reg("小花")  // 没有传入密码,使用默认值123456
    reg("小白")("admin")

  }
}

转换规则

隐式转换确实非常的强大,但是,在具体的使用过程中,我们要遵循一些特定的转换规则。

具体来说有两点:无歧义规则,不能多次转换。下面我们分别来解释

 

规则1:无歧义规则:不能重新定义两个相同的转换函数。如果有两个隐式转换函数,只有函数名不同,则会导致错误。

来结合具体的代码说明

如下的代码会导致编译错误。

implicit def fun1(a: String): Int = a.toInt
  implicit def fun2(a: String): Int = a.toInt

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

    val i:Int = "100"

  }

屏幕截图 2025-12-29 092107.png

规则2:不能多次转换:在一次转换过程中可以把A->B,B->C,但是不能直接从A->C。

package imp

// 隐式转换规则
//    1.无歧义规则:不能重新定义两个相同的转换函数!
//    2.不能多次转换:在一次转换中: A -> B,B -> C。不能A -> C


object imp03 {
  class KM(var value:Double) {override def toString:String = s"${value}千米"}
  class BM(var value:Double) {override def toString:String = s"${value}百米"}
  class M(var value:Double) {override def toString:String = s"${value}米"}

  implicit def km2bm(km:KM):BM = new BM(km.value*10)
  implicit def bm2m(bm:BM):M = new M(bm.value*100)
  implicit def km2m(km:KM):M = new M(km.value*1000)//为后添加

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

    val km = new KM(1.1)
    val bm:BM = km
    println(km)
    println(bm)

    val m:M = bm
    println(m)

    val m1:M = new KM(2)
    println(m1)

  }
}

屏幕截图 2025-12-29 093052.png

作用域

先说一个不能放的位置:implicit 不能放在顶级作用域(不能放在类的外边)看如下代码,就会报错

在实际的操作过程中,我们建议把它定义在如下两个地方:

1.包对象。这样在这个包下的所有类和对象中都可以使用,并且不需要额外的引入语句。

  1. 一个单独的文件定义中。这样在其他需要的位置就可以直接导入,然后使用。
package implications

object Implictions {
  implicit def double2Int(x:Double):Int = {
    println("double to int...")
    x.toInt
  }

}

在其他需要使用的地方导入:

import implication.Implications._

屏幕截图 2025-12-29 102528.png