Scala的隐式转换和隐式参数
- 1. 隐式转换
- 1.1 概述
- 1.2 使用步骤
- 2. 隐式参数
- 2.1 概述
- 2.2 使用步骤
- 3. 案例:获取列表元素平均值
隐式转换和隐式参数是Scala有特色的功能(Java没有),我们能利用隐式转换来丰富现有类的功能。在后续编写Akka并发编程,Spark、Flink程序时都会用到它们。
- 隐式转换 - 用
implicit关键字
声明的带有单个参数的方法 - 隐式参数 - 用
implicit关键字
修饰的变量
注意:implicit关键字
是在Scala 2.10版本出现的
1. 隐式转换
1.1 概述
隐式转换,指以implicit关键字
声明的带有单个参数的方法。该方法是自动被调用的,用来实现自动将某种类型的数据转换为另一种类型的数据。
1.2 使用步骤
- 在
object单例对象
中定义隐式转换方法 - 在需要用到隐式转换的地方,引入隐式转换(类似于导包,通过
import关键字
实现) - 当需要用到隐式转换方法时,程序会自动调用
示例一:手动导入隐式转换方法
import java.io.File
object ClassDemo {
//1.定义RichFile类,用来丰富File类的功能
class RichFile(file:File) {
//定义read()方法,用来将数据读取到一个字符串中
def read() = Source.fromFile(file).mkString
}
//2.定义单例对象InmplicitDemo,该单例对象中有一个隐式转换方法
object ImplicitDemo {
//隐式转换方法file2RichFile,用来将File对象转换成RichFile对象
implicit def file2RichFile(file:FIle) = New RichFile(file)
}
def main(args:Array[String]):Unit = {
//3.核心细节:手动导入隐式转换
import ImplicitDemo.file2RichFile
//4.创建普通的File对象,尝试调用其read()功能
val file = new File("./data/1.txt")
/*
执行流程:
1.先找File类有没有read()方法,有就用
2.没有就去查看有没有该类型的隐式转换,将该对象转换成其他类型的对象
3.如果没有隐式转换,直接报错
4.如果可以将该类型的对象升级为其他类型的对象,则查看升级后的对象中有没有指定的方法,有就用;没有就报错
*/
//5.打印结果
println(file.read())
}
}
示例二:自动导入隐式转换方法
在Scala中,如果在当前作用域中有隐式转换方法,会自动导入隐式转换。
import java.io.File
object ClassDemo {
//1.定义RichFile类,用来丰富File类的功能
class RichFile(file:File) {
//定义read()方法,用来将数据读取到一个字符串中
def read() = Source.fromFile(file).mkString
}
def main(args:Array[String]):Unit = {
//2.定义一个隐式转换方法,用来将File对象转换成RichFile对象
implicit def file2RichFile(file:File) = new RichFile(file)
//3.创建普通的File对象,尝试调用其read()功能
val file = new File("./data/1.txt")
//4.打印结果
println(file.read())
}
}
2. 隐式参数
2.1 概述
Scala方法中,可以带有一个标记为implicit的参数列表
。调用该方法时,此参数列表可以不用给初始化值,因为编译器会自动查找缺省值,提供给该方法。
2.2 使用步骤
- 在方法后面添加一个参数列表,参数使用implicit修饰
- 在object中定义implicit修饰的隐式值
- 调用方法,可以不传入implicit修饰的参数列表,编译器会自动查找缺省值
示例:
方式一:手动导入
object ClassDemo {
//1.定义show()方法,接收一个姓名,再接收一个指定的前缀,后缀信息,然后按照指定格式拼接
//细节:前缀和后缀信息时通过隐式参数设置实现的
def show(name:String)(implicit delimit:(String, String)) = delimit._1 + name + delimit._2
//2.定义一个单例对象,用来给隐式参数设置默认值
object ImplicitParam {
//implicit val delimit_defauly = ("<<<", ">>>")
implicit val delimit_defauly = "<<<" => ">>>")
}
def main(args:Array[String]):Unit = {
//3.核心细节:手动导入:隐式参数的值
import ImplicitParam delimit_default
//4.尝试调用show()方法,并打印结果
println(show("lee"))
println(show("mike")("((","))"))
}
}
//<<<lee>>>
//((mike))
方式二:自动导入
object ClassDemo {
//1.定义show()方法,接收一个姓名,再接收一个指定的前缀,后缀信息,然后按照指定格式拼接
def show(name:String)(implicit delimit:(String, String)) = delimit._1 + name + delimit._2
def main(args:Array[String]):Unit = {
//2.通过隐式值,来给隐式参数设置初始化值
//由程序自动导入
implicit val delimit_default = "<<<" => ">>>"
//4.调用show()方法,并打印结果
println(show("lee"))
println(show("mike")("(",")"))
}
}
//<<<lee>>>
//(mike)
3. 案例:获取列表元素平均值
object ClassDemo {
//1.定义RichList类,获取列表中所有元素的平均值
class RichList(list:List[Int]){
//2.定义avg()方法,用来获取列表中所有元素的平均值
def avg() = {
if(list.size == 0) None
else Some(list.sum / list.size)
}
}
def main(args:Array[String]):Unit = {
//3.核心步骤:定义隐式转换方法,用来将普通的List列表 -> RichList对象
//自动导入隐式方法
implicit def list2RichList(list:List[Int]) = new RichList(list)
//4.定义List列表,调用avg()方法,获取所有元素的平均值
val list = List(1, 2, 3, 4, 5)
println(list.avg())
}
}
//Some(3)