隐式转换--基本
// 关键字:implicit
// 隐式函数必须要在作用域范围内定义
// 隐式转换函数的 函数名自定义
// 隐式函数可以有多个,但是不能有重复的(函数名不能有重复,参数不能有重复)
// 代码中有下划线的地方表示使用了隐式转换
implicit def f1(d: Double): Int { d.toInt} // 将double类型数据转换为int型
implicit def f2(d: Float): Int { d.toInt}
// 将Double或Float数据赋值给 int 型,调用了隐式转换
val num: Int = 3.5 // 底层编译 f1$1(3.5)
/////////////////////////////////////////////////////////////////////////////
// 可以通过隐式行数丰富类库的功能,比如
// 定义一个ms对象,只有insert方法
class MS{
def insert(): Unit = {
println("insert")
}
}
// 再定义一个db对象,有delete方法
class DB {
def delete(): Unit = {
println("delete")
}
}
// 定义隐式函数,返回 DB对象
implicit def addDelete(ms: MS): DB = {
new DB
}
val ms = new MS
ms.insert() // ms对象的方法
ms.delete() // 隐式函数中的db的方法
隐式转换--进阶
隐式参数优先级
1、传入值 > 隐式值 > 默认值
2、在隐式匹配时候,不能同时匹配多个
3、如果3个一个都没有,就会报错
// 定义字符串隐式值为 jack~
implicit val str1: String = "jack~"
// 参数使用了隐式变量,其值为上面定义的隐式变量
def hello(implicit name: String): Unit = {
println("hello " + name)
}
// 不用传入参数,即可输出数据:hello jack~
hello
////////////////////////////////////////////
implicit val str1: String = "jack~"
// 参数中的 隐式变量使用了默认值,其优先级低于隐式值
def hello(implicit name: String = "scala"): Unit = {
println("hello " + name)
}
// 不用传入参数,输出数据:hello jack~
hello
////////////////////////////////////////////
implicit val name: Int = 10
// 参数中匹配不到隐式值,会使用默认值
def hello(implicit name: String = "scala"): Unit = {
println("hello " + name)
}
// 不用传入参数,输出数据:hello jack~
hello
////////////////////////////////////////////
implicit val str1: String = "jack~"
def hello(implicit name: String): Unit = {
println("hello " + name)
}
// 传入值,优先级大于隐式值,输出数据:hello scala
hello("scala")
隐式转换--高阶
隐式类
// 隐式类必须在类、包对象、或伴生对象里面,不能单独在外面(顶级),因为其作用域不能确定
// 隐式类不能用于 样例类
class Ms{
def sayOk():Unit = {
println("sayOk")
}
}
def main() = {
implicit class db(val m: Ms) {
def addSuffix(): String = {
m + " scala"
}
}
val ms new Ms //创建一个Ms实例
ms.sayOk() // 调用自己的方法
ms.addSuffix() // 这个是隐式类的方法,因为传入了Ms后,创建了实例包含了此方法
}
其他
隐式转换的时机
1、当方法中的参数类型与目标类型不一致时
2、当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换(根据类型)
隐式转换的陷阱
1、不能存在二义性,即多个隐式
2、不能嵌套使用:即隐式函数A如果是将小数转换为int,在隐式函数A中,不能使用 int=小数的情况。