隐式转换和隐式值
文章目录
1. 隐式转换
1.1 隐式函数基本介绍
- 隐式转换函数是以
implicit
关键字声明的带有单个参数的函数。这种函数会自动应用,将值从一种类型转换为另一种类型。
1.2 快速入门
object ImplicitDemo01 {
def main(args: Array[String]): Unit = {
//编写一个隐式函数转成 Double->Int 转换
//隐式函数应当在作用域才能生效
implicit def f1(d:Double): Int = { //底层生成 f1$1
d.toInt
}
val num: Int = 3.5 // 底层编译 f1$1(3.5)
println("num =" + num) // 3
}
}
1.3 隐式转换的注意事项和细节
- 隐式转换函数的函数名可以是任意的,隐式转换与函数名称无关,只与函数的参数类型和返回值有关。
- 隐式函数可以有多个,但需要保证在当前环境下,只有一个隐式函数能被识别。
2. 隐式转换丰富类库功能
-
案例代码
object ImplicitDemo02 { def main(args: Array[String]): Unit = { // 编写一个隐式函数,丰富MySQL功能 implicit def addDelete(mysql: MySQL): DB = { new DB } // 创建mysql对象 val mysql = new MySQL mysql.insert() mysql.delete() // 编译器工作 addDelete$1(mysql).delete() } } class MySQL { def insert() { ... } } class DB { def delete() { ... } }
3. 隐式值
3.1 基本介绍
- 隐式值也叫隐式变量,将某个形参变量标记为
implicit
,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省参数。
3.2 快速入门
object ImplicitValDemo {
def main(args: Array[String]): Unit = {
implicit val str: String = "zgl" // 隐式值
def hello(implicit name: String): Unit = { // implicit name: String 为隐式参数
println(name + ", hello!")
}
hello // 调用输出:zgl, hello! 底层:hello$1(str)
}
}
3.3 隐式值、默认值、传值的优先级
- 当在程序中,同时有隐式值、默认值、传值,编译器的优先级为:传值 > 隐式值 > 默认值。
- 在隐式值匹配时,不能有二义性。
- 如果三个(隐式值、默认值、传值)一个都没有,就会报错。
4. 隐式类
4.1 基本介绍
- 可以使用
implicit
声明类,隐式类非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要作用。
4.2 特点
- 其所带的构造参数有且只能有一个。
- 隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的(
top-level objects
)。 - 隐式类不能是
case class
(样例类)。 - 作用域内不能有与之相同的标识符。
4.3 案例
object ImplicitClass {
def main(args: Array[String]): Unit = {
// 隐式类
implicit class DB(val m: MySQL) { // 底层:ImplicitClass$DB$1
def addSuffix() {
...
}
}
// 创建 MySQL 实例
val mysql = new MySQL
mysql.insert() // 调用自身方法
mysql.addSuffix() // 使用隐式类 DB$1(mysql).addSuffix()
}
}
class MySQL {
def insert() {
...
}
}
5. 隐式转换时机
- 当方法中的参数类型与目标类型不一致时,或者是赋值时。
- 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换。