一、隐式参数
1.1 定义
定义一个普通变量,使用 “implicit” 关键字修饰,定义一个函数调用这个变量当参数时,此时这个参数就被称为 隐式参数
隐式参数的作用:减少提供函数参数的数量,让某些参数拥有隐藏的值(隐式变量)
1.2 示例
例①:
implicit val num:Int = 10 //定义一个Int类型的隐式参数
def sum(a:Int)(implicit num :Int):Int={ //隐式参数放入到普通函数中
a+num
}
//测试
println(sum(10)) //20
注:
- 这里定义的变量名是 num ,但是传入到函数当中,隐式参数名可以不为 num,随便起什么名字都可以,只要是 Int 类型就可以
- 在一个类中,定义同一类型的隐式参数只能有一个,即函数参数列表中同一类型的隐式参数也只能为一个,多了会打架,比如定义了两个Int类型的变量当参数,
implicit val a:Int = 10, implicit val b:Int = 20
,传入到函数中scala编译就不知道用哪个参数了 - 在一个类中,不同类型的隐式参数可以传入到函数当中
- scala中函数的传参级别: 函数列表传参 > 隐式参数 > 默认值
例②:
implicit val num:Int = 10 //定义一个Int类型的隐式参数num
implicit val say:String="Hello scala" //定义一个String类型的隐式参数say
def sum(a:Int)(implicit b :Int,str:String):Int={ //请注意这里传参时,我将 num 改成了 b,say 改成了str ,证明隐式参数只认类型
println(str)
a+b
}
//测试
println(sum(10))
//控制台输出:
//Hello scala
//20
二、隐式函数
2.1 定义
通常我们所说的隐式函数也称为 隐式转换,是使用 implicit 修饰的函数
作用: 可以通过一个隐式函数将一种类型转变为另一种类型
隐式转换有两种应用场景:
- 类型转换,隐式转换为期望类型
- 类型增强
2.2 示例
①:类型转换
在java中,当我们申明一个变量a 为 Int 类型,赋值为 3.5 ,这时就会直接报错,scala也一样
但是在scala中定义一个隐式函数,函数体是将传入的 Double 类型使用 toInt 方法转为 Int 类型就可以解决这个问题
implicit def doubleToInt(obj:Double) = obj.toInt //定义隐式函数
val a:Int = 3.5 //写的时候scala就调用了隐式函数 doubleToInt 进行类型转化
常用的类型转换:
implicit def doubleToString (obj:Double):String=obj.toString
implicit def intToString(obj:Int):String=obj.toString
implicit def stringToInt(obj:String):Int=Integer.parseInt(obj)
对象的类型转换见下文 -----> 3.2示例
②:类型增强
比如说 1+true 这个表达式,我们想让 true当作 1计算, false当作 0计算。
Int 类型与boolen类型是无法相加的,编译器肯定会报错
此时,我们可以定义一个隐式函数,使 “true=1,false=0” ,此时便可提供一个隐式函数,使得Int+Boolean成立
implicit def booleanToInt(obj:Boolean)=if(obj) 1 else 0
//测试
val a=1+true
println(a) //2
注: 隐式转换的发生时机
-
当方法中的参数的类型与目标类型不一致时
-
当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
三、隐式类
3.1 定义
隐式类指的是用implicit关键字修饰的类。在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换。
3.2示例
现在有一个需求:有一个 Person 类,含有work()方法,有一个 Student 类,含有study()方法,在不使用继承的情况下,要求创建一个Person类的对象,可以直接调用Student类里的study()方法?
方法①: 使用 隐式类 ,将Student类定义为隐式类,这样在 new Person对象的时候, 编译器会默认在Student的主构造方法中传入Person对象,再转型为Student对象,这样新建的Person对象就有了双重身份,可以随便调用这两个类中的方法
代码如下:
创建一个scala class文件: Person
class Person() { //定义一个主类:Person 有个work方法
def work()={
println("人每天都要工作")
}
}
object Test1{
implicit class Student(obj:Person){ //在object中定义一个隐式类:Student 有个study方法
def study()={ //圈重点:主构造方法传入的类型必须要有-----> Person
println("喜欢学习scala")
}
}
def main(args: Array[String]): Unit = {
val person: Person = new Person //在main方法中new一个Person对象
person.work()
person.study() //可以看到可以直接调用Student中的study()方法
}
}
注:
- 创建隐式类,主构造函数中必须要引入一个目标类当参数,且隐式类必须要在 object 中创建
- 本文是将隐式类与目标类写在了一个scala文件中,当隐式类写在其他文件中,调用时引入该隐式类所在的包即可
方法②: 使用 隐式函数 转换,创建Person对象时,编译器默认会将Person对象转为Student对象,从而使得新建的Person对象有了双重身份,可以随便调用这两个类中的方法
代码如下:
创建一个scala class文件: Person
class Person() { //定义一个主类:Person 有个work方法
def work()={
println("人每天都要工作")
}
}
class Student(){ //定义一个普通类:Student 有个study方法
def study()={
println("喜欢学习scala")
}
}
object Test1{
//圈重点:定义一个隐式函数,将 Person 转为 Student
implicit def personToStudent(obj:Person):Student = new Student
def main(args: Array[String]): Unit = {
val person: Person = new Person //在main方法中new一个Person对象
person.work()
person.study() //可以看到可以直接调用Student中的study()方法
}
}
注:
- 使用隐式函数,Studnet类只需定义为一个普通类即可
- Person类可以使用多个隐式函数转型,从而使用其他类中的方法