隐式转换函数指的是以implicit关键字声明的带有单个参数的函数。这样的函数将被自动应用,将值以一种类型转换成另一种类型。隐式转换函数通常不会由用户手动调用,而是由Sacala进行调用。如果要进行隐式转换,则需要对隐式转换函数进行导入(import)。因此通常建议将饮食转换函数的名称命名为"one2one
"的形式。
常用使用方式:
- 隐式值
- 隐式参数
- 参数的隐式转换
- 隐式类
Scala会考虑如下位置的隐式转换函数:
- 位于源或目标类型的伴生对象中的隐式函数
- 位于当前作用域可以以单个标识符指代的隐式函数
隐式转换在如下三种不同情况下会被考虑:
- 当表达式类型与预期类型不同时
- 当对象访问一个不存在成员时
- 当对象调用某个方法,而这个方法的参数声明与传入参数不匹配时
有三种情况编译器不会尝试使用隐式转换:
- 如果代码能够在不适用隐式转换的前提下通过编译,则不会使用隐式转换
- 编译器不会尝试同时执行多个转换
- 存在二义性的转换是错误
隐式值
类易于缺省值
def ImplicitConvertExample{
//声明值(缺省值)
implicit val name : String ="zs"
implicit val age : Int = 10
def main(args: Array[String]):Unit = {
//获取隐式值 implicitly[泛型]
val iName = implicitly[String]
val iAge = implicitly[Int]
println(iName + "|" +iAge)
}
}
注意:同类型的隐式值只能有一个
隐式参数
将方法或者函数的形参生命为implicit,要求在源文件中提供同类型的隐式值(缺省值或者默认值)
object ImplicitConverExample{
//声明值(缺省值)
implicit val name: String ="zs"
implicit val y: Int = 10
def main(args: Array[String]): Unit={
// 获取隐式值 implicitly[泛型]
sayHi
sayHi("ls")
println(sum(10))
println(sum(10)(20))
}
//implicit 形参参数 调用sayHi 可以不给形参iName赋值,会自动寻找是否有同类型的隐式值存在
//隐式转换:当编译不通过时 会触发隐式转换处理
def sayHi(implicit iName: String):Unit = {
println("hi:" + iName)
}
def sum(x : Int)(implicit y : Int): Int = {
x + y
}
}
参数的隐式转换(隐式转换函数)
object ImplicitConvertExample01 {
def main(args: Array[String]): Unit = {
// 正常操作
// sayHi(new Student("zs"))
// say要求的类型是 Student 而传递是 String
// 编译不通过时 自动触发 提供一个隐式转换函数 str ---> Student
sayHi("zs")
}
// 隐式转换函数
// one2one
implicit def str2Student(str: String): Student = {
println("--------------")
new Student(str)
}
def sayHi(stu: Student): Unit = {
println("学生的姓名:" + stu.name)
}
}
class Student(var name: String) {
}
object ImplicitConvertExample02 {
def main(args: Array[String]): Unit = {
val man = new Man("zs")
// man类中没有提供fly方法,会编译出错
// 定义隐式转换函数 在编译不通过时将man类型自动转换为superMan 实现fly方法调用
man.fly
}
implicit def man2SuperMan(man: Man): SuperMan = {
new SuperMan(man.name)
}
}
class Man(var name: String)
class SuperMan(var name: String) {
def fly {
println("flying....")
}
}
隐式类
通过隐式类构造方法实现隐式转换的处理
object ImplicitConvertExample03 {
def main(args: Array[String]): Unit = {
val man2 = new Man2("zs")
// man类中并没有提供fly方法,会编译出错
// 定义隐式转换函数 在编译不通过时将man类型自动转换为superMan 实现fly方法调用
man2.fly
// 隐式类方式实现
implicit class SuperMan2(man2: Man2) { // Man2 ---> SuperMan2
var name: String = _
def fly = {
this.name = man2.name
println("flying ...")
}
}
}
}
class Man2(var name: String)
注意:
- 隐式类只能在特质,类,对象内部定义,不能独立声明
- 隐式类构造函数只能携带一个非隐式参数
- implicit关键字不能应用于scala case类
通过隐式转换实现Java集合和Scala集合的互操作↓
object ImplicitConvertExample04 {
def main(args: Array[String]): Unit = {
val list1: java.util.ArrayList[String] = new util.ArrayList[String]();
list1.add("a")
list1.add("b")
list1.add("c")
val scalaCollection = list1.asScala
val newCollection = scalaCollection :+ "d" // scala操作方法
println(newCollection.mkString(","))
val javaList = newCollection.asJava
javaList.add("e")
}
}
如何导入外部的隐式转换
object ImplicitConvertExample02 {
def main(args: Array[String]): Unit = {
val man3 = new Man3("zs")
// 如果:
// 1. 隐式转换定义在类class中,需要通过import 导入隐式转换,具体方法是 先创建类 然后通过的类的引用名._
// import man3._
// man3.fly
// 2. 隐式转换定义在对象object中,需要通过import导入隐式转换 具体方法是:import 单例对象._
import TestAA._
man3.fly
}
}