11_Scala_OOP_03_隐式转换_函数_值_类
隐式函数
隐式转换函数(implicit关键字声明) 的带有单个参数的函数。自动应用,将值从一种类型转换为另一种类型
隐式转换细节
1 隐式转换与函数名称无关,只与函数签名(函数参数类型和返回值类型)有关
2 保证在当前作用域下,只有一个隐式函数能被识别->避免冲突
3 丰富类库功能 例 一个类增加一个方法,可以通过隐式转换来动态增加该功能来实现
object ImplicitTest01 {
def main(args: Array[String]): Unit = {
//隐式转换函数(implicit关键字声明) 的带有单个参数的函数。自动应用,将值从一种类型转换为另一种类型
implicit def Impld (d: Double) :Int ={
d.toInt
}
//1 与函数名称无关,只与函数签名(函数参数类型和返回值类型)
implicit def Implf (f: Float) :Int ={
f.toInt
}
// 2 保证在当前作用域下,只有一个隐式函数能被识别,避免冲突, 此处两个函数签名相同的隐式转换函数, var num: Int = 4.5f 会报错
implicit def Implf2 (f: Float) :Int ={
f.toInt
}
var num: Int = 4.5f
var num1: Int = 3.66666666
println(num + " \t" + num1)
// 3 丰富类库功能 例 一个类增加一个方法,可以通过隐式转换来动态增加该功能来实现
implicit def addBBB(aa: AA) : BB={ // 传入AA 返回BB 对象
new BB
}
val alex = new AA
alex.BBB_1() // 隐式转换时机 2 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
alex.BBB_2() // 底层: implicit def addBBB$1(alex).BBB_2 implicit def addBBB(alex) 返回一个 BB 对象
// 隐式转换时机
// 1 当方法中的参数的类型与目标类型不一致
// 2 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
def implict_time(n1: Int){println(" 隐式转换时机")}
// implicit def Implf (f: Float) :Int ={
// f.toInt
// }
implict_time(20.1f)
class AA {
def AA(): Unit = { println("AA") }}
class BB {
def BBB_1(): Unit = { println("BBB_1") }
def BBB_2(): Unit = { println("BBB_2")}
}
隐式值(隐式变量) & 优先级
将形参变量标记为implicit,编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省(默认)参数 (默认值只能作用在一个形参,隐式值可以作用在多个函数上)
object ImplicitPriority {
def main(args: Array[String]): Unit = {
//将形参标记为implicit,编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省(默认)参数
implicit var str: String = "Alex "
// sayHi
sayHello // hello Alex 隐式值优先级大于默认值
sayHello("Sumi") //hello Sumi 实参优先级大于隐式值
}
def sayHi(implicit name: String): Unit = {
println("hi " + name) //hi alex
}
// 优先级问题 隐式值,默认值,实参
// 优先级: 实参 > 隐式值 > 默认值
// 如无 隐式值,仍使用默认值
def sayHello(implicit name: String ="Bob"): Unit = {
println("hello " + name)
}
}
隐式类 implicit声明类,同样可以扩展类的功能
object ImplicitClass {
def main(args: Array[String]): Unit = {
//1 其所带的构造参数有且只能有一个
//2 隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是 顶级的(top-level objects) 不能跟包对象平级,无法确定作用域
//3 隐式类不能是case class
//4 作用域内不能有与之相同名称的标识符 不能有俩同名的 implicit class Gauss 和 class Gauss
//implicit声明类,同样可以扩展类的功能
//Gauss 生成隐式类ImplicitClass.MRS.1 MRS$2(DWS d) main 函数内 有个$2 在作用域内 创建DWS实例 编译器就会让隐式类生效
//返回一个 ImplicitClass.MRS.1(d) 实例 该实例中有个方法 public void addMRS() { Predef..MODULE$.println("MRS");}
// dws.addMRS() 就是调用的 MRS$2(dws).addMRS
implicit class Gauss(val m : MySQL) {
def addGaussMethod(): String ={ m + "Gauss"}
def addGaussInsert(): Unit = {
println("addGaussInsert")
}
}
implicit class MRS (var d: DWS) { //ImplicitClass.MRS.1 MRS$2(DWS d)
def addMRS() {println("MRS")}
}
val m1 = new MySQL
m1.sayOk() //sayMySQL
println(m1.addGaussMethod()) //com.chapter09_conversion.MySQL@763d9750Gauss
m1.addGaussInsert() //addGaussInsert
val dws = new DWS
dws.addMRS() //MRS$2(dws).addMRS
}
}
class Gauss {}
class MRS {}
class DWS {}
class MySQL {
def sayOk(): Unit = {println("sayMySQL")}
}
隐式解析机制 (转载)
即编译器是如何查找到缺失信息的,解析具有以下两种规则:
情况1 首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)
情况2 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下
a) 如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索。
b) 如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的伴生对象和String的伴生对象。
c) 如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索。
d) 如果T是个类型注入S#T,那么S和T都会被搜索。
- 点赞
- 收藏
- 关注作者
评论(0)