目录

  • ​​scala outline​​
  • ​​scala 隐式转换​​
  • ​​scala 隐式转换触发时机​​
  • ​​scala 手动导入隐式函数​​
  • ​​scala 自动导入隐式函数​​
  • ​​scala 隐式参数​​
  • ​​scala 隐式类​​
  • ​​隐式解析机制​​

scala outline

​​scala outline​​

scala 隐式转换

scala中通过implicit关键字修饰的变量、函数或者类,在调用时,不用显式书写调用过程的一种语法

​隐式转换目的:​​ 扩展功能

scala 隐式转换触发时机

当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范围内查找是否有对应功能的转换规则,如果有,编译器会自动调用这个转换规则

scala 手动导入隐式函数

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

需求:通过隐式转换, 让File类的对象(File类的对象不具有read功能)具备有read功能,即: 实现将文本中的内容以字符串形式读取出来

import java.io.File
import scala.io.Source

// 1. 定义一个RichFile类, 用来给普通的File对象添加 read()功能
class RichFile(file: File) {
// 定义一个read()方法,用来读取数据
def read(): String = {
Source.fromFile(file).mkString
}
}

// 2. 定义一个单例对象,包含一个方法,该方法用于将:普通的File对象 转换成 RichFile对象
object Demo {
//定义一个方法, 该方法用于将: 普通的File对象 转换成 RichFile对象
implicit def file2RichFile(file: File): RichFile = {
new RichFile(file)
}
}

object Test01 {

def main(args: Array[String]): Unit = {
// 3. 非常重要的地方: 手动导入 隐式转换
import Demo.file2RichFile
// 4. 创建普通的File对象, 尝试调用其read()功能
val file = new File("E:\\input\\hello.txt")
/*
执行流程:
1. 先找File类有没有read(), 有就用
2. 没有,就去查看是否有该类型的隐式转换,将该对象转成其他对象
3. 如果没有隐式转换, 直接报错
4. 如果可以将该对象升级为其他对象, 则查看升级后的对象中有没有指定方法, 有, 不报错, 没有就报错
如下的案例执行流程:
1. file对象中没有read()方法
2. 检测到有隐式转换将 file对象 转成 RichFile对象
3. 调用RichFile对象的read()方法,打印结果
*/
println(file.read())
}
}

scala 自动导入隐式函数

import java.io.File
import scala.io.Source

// 1. 定义一个RichFile类, 用来给普通的File对象添加 read()功能
class RichFile(file: File) {
// 定义一个read()方法,用来读取数据
def read(): String = {
Source.fromFile(file).mkString
}
}

object Test01 {
def main(args: Array[String]): Unit = {
// 2. 自定义一个函数, 该函数用implicit修饰,用来将: 普通的File -> RichFile, 当程序需要使用的时候, 会自动调用
implicit def file2RichFile(file: File): RichFile = {
new RichFile(file)
}

// 3. 创建File对象, 调用read()方法
val file = new File("E:\\input\\hello.txt")
println(file.read())
}
}

scala 隐式参数

隐式参数: 指的是用 implicit关键字 ​​修饰的变量​

普通方法或者函数中的参数可以通过implicit关键字声明为隐式参数,调用该方法时,编译器会在相应的作用域寻找符合条件的隐式值

def main(args: Array[String]): Unit = {
implicit val str: String = "cuihua"

// 函数中的参数name可以通过implicit关键字声明为隐式参数
def say(implicit name: String): Unit = {
println("hello:" + name)
}
say // 调用该方法时,编译器会在相应的作用域寻找符合条件的隐式值str
}

​注意:​

  1. 同一个作用域中,相同类型的隐式值只能有一个
def main(args: Array[String]): Unit = {
implicit val str: String = "cuihua"
implicit val str1: String = "fengjie" // 错误 同一个作用域中,相同类型的隐式值只能有一个

def say(implicit name: String): Unit = {
println("hello:" + name)
}
say
}

输出

hello:cuihua
  1. 隐式参数优先于默认参数
def main(args: Array[String]): Unit = {
implicit val str: String = "cuihua"

def say(implicit name: String="fengjie"): Unit = {
println("hello:" + name)
}
say // 输出:hello:cuihua
}

scala 隐式类

在​​Scala2.10​​​后提供了​​隐式类​​​,可以使用implicit声明类,隐式类的非常强大,同样可以扩展类的功能,​​在集合中​​隐式类会发挥重要的作用

(1)其所带的构造参数有且只能有一个

(2)隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的

import java.io.File
import scala.io.Source

object Test01 { // 隐式类 RichFile 被包裹在伴生对象 Test01 中
implicit class RichFile(file: File) {
def read(): String = {
Source.fromFile(file).mkString
}
}

def main(args: Array[String]): Unit = {
val file = new File("E:\\input\\hello.txt")
println(file.read())
}
}

隐式解析机制

  1. 首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)
  2. 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找

​例如​​ 隐式参数使用的优先顺序为:

(1)当前类声明的implicits
(2)导入包中的 implicits
(3)外部域(声明在外部域的implicts)
(4)继承的父类中的
(5)所属包对象中的
(6)伴生对象的以上作用域