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 使用步骤

  1. object单例对象中定义隐式转换方法
  2. 在需要用到隐式转换的地方,引入隐式转换(类似于导包,通过import关键字实现)
  3. 当需要用到隐式转换方法时,程序会自动调用

示例一:手动导入隐式转换方法

使用 spark bitmap 统计uv spark implicit_ci


使用 spark bitmap 统计uv spark implicit_ci_02

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中,如果在当前作用域中有隐式转换方法,会自动导入隐式转换。

使用 spark bitmap 统计uv spark implicit_scala_03

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 使用步骤

  1. 在方法后面添加一个参数列表,参数使用implicit修饰
  2. 在object中定义implicit修饰的隐式值
  3. 调用方法,可以不传入implicit修饰的参数列表,编译器会自动查找缺省值

示例:

使用 spark bitmap 统计uv spark implicit_scala_04


方式一:手动导入

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. 案例:获取列表元素平均值

使用 spark bitmap 统计uv spark implicit_scala_05


使用 spark bitmap 统计uv spark implicit_scala_06

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)