前言
对于 Spark 开发者来说 Scala 终究是个绕不过去的坎, 而 对于 Scala ,隐式转换终究也是一个绕不过去的坎。 所以本文就以一种尽可能简单的方式带大家来理解一下 Scala 的隐式转换。
Scala隐式转换 是什么?
- 隐式转换 这里我没有找到具体的定义, 这里我们就用大白话来说一下, 如果我们想让一台汽车具有挖土机的功能, 那么我们需要给这个汽车装上一个挖机铲, 如果装这个挖机铲需要我自己买来装, 那我们就说是显示转换, 如果这个挖机铲有人给我自动装上了, 并且我都不知道到底这个人是谁,是怎么给我装上的, 那这就是隐式转换。 ok,这里我们先记住这个小栗子, 后面我们用代码来实现的时候你就会有更进一步的理解
Scala隐式转换 的使用
- 隐式参数 二话不说,我们先上个列子, 然后再来解释:
def main(args: Array[String]): Unit = {
//定义一个隐式参数
implicit val i_car: String = "*小汽车*"
def upgradeExcavator(implicit car:String): Unit ={
println("我将把 " car " 升级成 挖机")
}
//显示转换
upgradeExcavator(i_car)
//隐式转换
upgradeExcavator
}
- 我们定义了一个隐式参数
i_car
. - 接着我们定义了一个方法
upgradeExcavator
, 并接受一个参数,打印一句将传入的参数升级为 挖土机 - 然后我们显示的传入参数
i_car
,调用方法upgradeExcavator(i_car)
, 控制台打印我将把 *小汽车* 升级成挖机
- 然后我们直接调用方法
upgradeExcavator
,不传入任何参数 控制台也会打印我将把 *小汽车* 升级成挖机
。 很明显,系统自己将我们的i_car
当做了参数传入。
我们仔细观察就会发现,我们定义 i_car
的时候使用了 implicit
关键字修饰,
upgradeExcavator
的参数一样使用到了 implicit
关键字修饰,
当我们调用一个方法,其参数被 implicit
关键字修饰 的时候,
如果我们不传入参数,那么该方法就会去其作用域内寻找一个符合该类型的参数,
作为其默认的传入值
ok,这就是隐式参数,那么我们需要注意的是:
- 如果作用域内有多个符合规则的参数会怎么样呢? 报错,因为系统将不知道你要使用的是哪个参数, 这个时候你就只能使用显示转换了。
- 如果我需要传入隐式参数,同时也需要传入显示参数呢?怎么办?
这种需求我们需要使用 柯里化 函数才行,
类似这样
def upgradeExcavator(car2:String) (implicit car:String)={...}
这里Scala 高阶函数应用不在讨论之列, 所以就不多说了。 - implicit 关键字必须放在隐式参数定义的开头, 多个参数只需要在头部标注即可
- 隐式函数 同样的,我们先上代码
class Car() {
def name() = {
"普通小汽车"
}
}
class Excavator(car: Car) {
def name() = {
car.name() " 升级成的 挖土机"
}
def dig() = {
println("我具有挖掘功能")
}
}
def main(args: Array[String]): Unit = {
implicit def upgradeExcavator(car: Car) = {
new Excavator(car)
}
val car = new Car
println(car.name())
car.dig()
}
- 我们定义了一个
Car
类,其有一个name
方法返回其名字 - 我们定义了一个
Excavator
类,其有一个name
方法返回其名字, 和一个挖掘的功能函数dig
- 我们创建一个隐式函数,该函数接受一个
Car
对象,并返回一个Excavator
- 我们创建一个
Car
实例,打印去名字 - 神奇的是,我们竟然可以
car.dig()
,我们的小汽车竟然有挖掘功能
这就是隐式函数,当我们创建了一个对象Car
,并调用不属于该对象的方法dig
的时候。
那么系统会去作用域内寻找一个隐式函数,
如果他能找到这么一个隐式函数——将 Car
转换成 Excavator
的函数,
那么你就可以直接把 Car
当做Excavator
使用
- 隐式类 隐式类其实和隐式方法很像,我们将上面的代码改一改, 很容易就得到以下这个代码:
class Car() {
def name() = {
"普通小汽车"
}
}
implicit class Excavator(car: Car) {
def name() = {
car.name() " 升级成的 挖土机"
}
def dig() = {
println("我具有挖掘功能")
}
}
def main(args: Array[String]): Unit = {
val car = new Car
println(car.name())
car.dig()
}
我们去掉了隐式方法,将Excavator
修改成了一个隐式类,
那么 当我们创建一个对象 Car
,并尝试去调用 dig
函数的时候,
系统会去其作用域内寻找是否有这么一个类,其构造函数接受一个 Car
,
如果有,那么我们就可以把 car
对象直接当Excavator
使用。
OK!到这里 隐式转换的相关使用知识差不多就是这样了, 这里我们多次提到作用域,所以隐式函数什么的, 是可以通过
import
来进行导入的, 这也就是隐式转换可以简化代码的一个重要原因,
本文既然是基于简明二字,所以没有太多的理论, 希望你看完之后会有一点帮助