25、Scala的隐式转换
文章目录
提出问题:隐式转换的存在,是因为在一些情况下,需要指定某些数据类型的转换。
一、隐式函数是什么?
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.8
println("num ="+num)
}
}
1.3 隐式转换的注意事项和细节
- 隐式函数的函数名是可以任意的,隐式转换与函数名称无关,只与隐式函数的签名(即隐式函数的参数类型和返回值类型)有关。
- 隐式函数可以有多个(即隐式函数列表);但是需要保证在当前环境下,只有一个隐式函数能被识别(即唯一性)
2.1 隐式转换丰富类库功能
2.1.1 隐式转换快速入门案例
object implicitDemo1 {
def main(args: Array[String]): Unit = {
//编写一个隐式函数 丰富mysql的功能
implicit def addDelete(mySQL: MySQL): DB = {
new DB
}
val mySQL = new MySQL
mySQL.insert()
mySQL.delete() //有下划线 表示存在隐式转换
}
}
//分析
/*
* 1 当将隐式函数放置于主函数下时,会生成addDelete$1(),之后传入addDelete$1(MySQL),返回一个db,之后调用delete方法.
* 2 当放在object对象下时,会有生成addDelete()调用mysql,然后返回一个DB名之后调用delete方法
* */
class MySQL {
def insert(): Unit = {
println("输出MySQL")
}
}
class DB {
def delete(): Unit = {
println("输出Delete")
}
}
3.1 隐式值
基本介绍:
隐式值也叫隐式变量,是将某个形参变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省参数.
3.1.1 快速入门案例
object implicitValDemo {
def main(args: Array[String]): Unit = {
implicit val str: String = "Jack ~ " //该声明为隐式值
//implicit name:String name是隐式参数
def sayHi(implicit word: String): Unit = {
println("Hello " + word)
}
sayHi //底层是 say("Jack ~")
}
}
小结:
- 当在程序中,有隐式值 、传值、默认值时,传值的优先级最高,之后是隐式值,之后是默认值
- 隐式值匹配时,不能有二义性
- 若是三个(隐式值、传值、默认值)都没有时,程序不能运行
4.1 隐式类
4.1.1 概述
在scala2.10之后提供了隐式类,可以用implicit声明类,隐式类非常强大,同样可以扩展类的功能,比前面使用隐式转换丰富类库更加方便,在集合中隐式类会发挥重要作用。
隐式类有如下特点:
- 其所带的构造参数有且只有一个
- 隐式类必须被定义在“类” 或者“伴生对象” 或者 “包对象”内,即隐式类不能是顶级的(top-level
object) - 隐式类不能是case clas
- 作用域内不能有与之相同名称的标识符
4.1.2 快速入门
object implicitClassDemo {
def main(args: Array[String]): Unit = {
//DB1会对应生成隐式类
//DB1 是一个隐式类,当我们在该隐式类的作用域范围内创建MySQL的实例是,该隐式类就会生效(内部又编译器处理)
implicit class DB1(val m: MysqlA) {
def addSuffix(): String = {
m + "Scala"
}
}
val mysqlA = new MysqlA
mysqlA.sayOK()
println(mysqlA.addSuffix())
}
}
class MysqlA {
def sayOK(): Unit = {
println("sayOk")
}
}
5 隐式转换时机
- 当方法中的参数类型和目标类型不一致时,或者是赋值时,会调用隐式转换
- 当对象调用所在类中不存在方法或者成员时,编译器会自动将对象进行隐式转换(根据类型)