十四、Scala的隐式转换和隐式参数


隐式转换和隐式参数是Scala有特色的功能(Java没有),我们能利用隐式转换来丰富现有类的功能。在后续编写Akka并发编程,Spark、Flink程序时都会用到它们。

  • 隐式转换 - 用implicit关键字声明的带有单个参数的方法
  • 隐式参数 - 用implicit关键字修饰的变量

注意implicit关键字是在Scala 2.10版本出现的

1. 隐式转换

1.1 概述

隐式转换,指以implicit关键字声明的带有单个参数的方法。该方法是自动被调用的,用来实现自动将某种类型的数据转换为另一种类型的数据。

1.2 使用步骤

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

示例一:手动导入隐式转换方法
在这里插入图片描述
在这里插入图片描述

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

  1. 在方法后面添加一个参数列表,参数使用implicit修饰
  2. 在object中定义implicit修饰的隐式值
  3. 调用方法,可以不传入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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值