详解 Scala 的隐式转换

当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将某个类型进行转换,实现二次编译通过

一、隐式函数

隐式函数可以在不修改任何代码的情况下,扩展某个类的功能

scala 复制代码
/**
	声明语法:
	implicit def funcName(param: Type1): Type2 = {}
*/
// 使用隐式函数扩展 Int 类型功能
object TestImplicitFunc {
    def main(args: Array[String]): Unit = {
        // 实现 12.myMax(15) 取最大值功能
        // val maxValue = 12.myMax(15) // Int 类型没有该方法
        
        // 1. 显式的将 Int 转换为 MyRichInt(通用性不强,每次调用都要手动转换)
        val myRichInt = new MyRichInt(12)
        println(myRichInt.myMax(15)) 
        
        // 2. 定义隐式函数转换(必须在方法调用之前定义)
        // 12.myMax(15) // 编译error
        implicit def convert(num: Int): MyRichInt = new MyRichInt(num)
        
        println(12.myMax(15))
        
    }
}

// 定义一个类,并声明要扩展的方法
class MyRichInt(val self: Int) {
    def myMax(num: Int): Int = if(num > self) num else self
    def myMin(num: Int): Int = if(num > self) self else num
}

二、隐式参数

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

scala 复制代码
/**
	定义:
		implicit val varName: Type = value
		func(implicit param: Type,...)
	特点:
		1.同一个作用域中,相同类型的隐式参数值只能有一个
		2.编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关
		3.隐式参数优先于默认参数
*/
object TestImplicitParam {
    def main(args: Array[String]): Unit = {
        implicit val str: String = "tom"
        // implicit val str2: String = "jack" // error
        implicit val num: Int = 18
        
        def sayHello()(implicit name: String): Unit = println("hello, " + name)
        def sayHi(implicit name: String = "jerry"): Unit = println("hi, " + name)
        sayHello
        sayHello()
        sayHi // tom,隐式参数优先于默认参数
        // sayHi() // error
        
        // 方法定义省略隐式参数声明,使用 implicitly[] 方法指定要的隐式参数值类型
        def printAge(): Unit = println("Age: " + implicitly[Int])
        printAge()
    }
}

三、隐式类

在 Scala2.10 后提供了隐式类,可以使用 implicit 声明类,可以扩展类的功能,相当于加强版隐式函数

scala 复制代码
/**
	定义语法:
		implicit class className(param: Type) {}
	要求:
		1.其所带的构造参数有且只能有一个
		2.隐式类必须被定义在"类"或"伴生对象"或"包对象"里,即隐式类不能是顶级的
*/
// 使用隐式类扩展 Int 类型功能
object TestImplicitClass {
    // 定义一个隐式类,并声明要扩展的方法(必须被定义在"类"或"伴生对象"或"包对象"里)
    implicit class MyRichInt(val self: Int) {
        def myMax(num: Int): Int = if(num > self) num else self
        def myMin(num: Int): Int = if(num > self) self else num
    }
    // 隐式类在方法调用之前定义
    
    def main(args: Array[String]): Unit = {
        println(12.myMax(15)) 
        println(12.myMin(15))
    }
    
}

四、隐式解析机制

  • 首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)
  • 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生对象以及该类型所在包的包对象
相关推荐
ACP广源盛139246256731 分钟前
M6/M5 Pro Mac mini 端侧 AI 爆发@ACP#YLB3118 存储扩展芯片在本地 AI 服务中的机会与落地场景
大数据·网络·数据库·人工智能·嵌入式硬件·macos
学逆向的3 分钟前
扩展PE头属性说明
开发语言·网络安全·pe
IT研究室9 分钟前
最新大数据毕业设计选题推荐-基于大数据的水质多指标关联分析与可视化的设计与实现-大数据-Spark-Hadoop-Bigdata
大数据·spark·课程设计
秋名RG12 分钟前
Java 基础语法
java·开发语言
程序员阿明12 分钟前
spring boot4+springAI 2加redis多轮对话存储
spring boot·redis·后端
故七月13 分钟前
产业观察|从 9 月行业数据看西南市场 GEO 落地现状与发展路径
大数据·人工智能
丶浅行DE时光16 分钟前
管道式电磁流量计选型指南 介质腐蚀与工况适配方案推荐
大数据·网络·人工智能·科技·推荐算法
码行山野赴时序归途16 分钟前
C 语言文件操作完全指南:从打开到关闭
c语言·开发语言
小白说大模型21 分钟前
Hermes 全配置指南:从裸版到 AI Agent 天花板
大数据·人工智能·学习·算法·机器学习·数据挖掘
2501_9378609423 分钟前
Java 文件操作与IO(下):字节流、字符流实战IO读写
java·开发语言·python