scala 隐式转换
隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型。
使用方式:
- 将方法或变量标记为implicit
- 将方法的参数列表标记为implicit
- 将类标记为implicit
隐式值:用于给方法提供参数
// 声明一个带有implicit修饰过参数的方法
def person(implicit name: String): name
// 我们不能直接 person , 这样调用, 但是可以
implicit val x = "mike" //x被称为隐式值
// 然后直接调用
person
隐式视图
隐式转换为目标类型:把一种类型自动转换到另一种类型
// 将整数转换成字符串类型:
def Int2String(x: String) = x.toString
隐式转换调用类中本不存在的方法
通过隐式转换,使对象能调用类中本不存在的方法
class DataFrame{
def sqlMethod(m : String) = println("使用DataFrame的sql方法:"+m)
}
object toDF{
implicit def dataSet2DataFrame(s : DataSet) = DataFrame
}
class DataSet
object DataSet extends App{
import toDF._
val ds = new DataSet
ds.sqlMethod("select") //使用DataSet中不存在的sql方法
}
隐式类
在scala2.10后提供了隐式类,可以使用implicit声明类
1.其所带的构造参数有且只能有一个
2.隐式类必须被定义在类,伴生对象和包对象里
3.隐式类不能是case class(case class在定义会自动生成伴生对象与2矛盾)
4.作用域内不能有与之相同名称的标示符
object StringUtils {
implicit class StringImprovement(val s : String){ //隐式类
def increment = s.map(x => (x +1).toChar)
}
}
object Main extends App{
import StringUtils._
println("mobin".increment)
}
官方文档中的用法:
创建隐式类时,只需要在对应的类前加上implicit关键字。比如:
object Helpers {
implicit class IntWithTimes(x: Int) {
def times[A](f: => A): Unit = {
def loop(current: Int): Unit =
if(current > 0) {
f
loop(current - 1)
}
loop(x)
}
}
}
这个例子创建了一个名为IntWithTimes的隐式类。这个类包含一个int值和一个名为times的方法。要使用这个类,只需将其导入作用域内并调用times方法。比如:
scala> import Helpers._
import Helpers._
scala> 5 times println("HI")
HI
HI
HI
HI
HI
使用隐式类时,类名必须在当前作用域内可见且无歧义,这一要求与隐式值等其他隐式类型转换方式类似。
注意事项
隐式转换的时机:
1.当方法中的参数的类型与目标类型不一致时
2.当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
隐式解析机制
即编译器是如何查找到缺失信息的,解析具有以下两种规则:
1.首先会在当前代码作用域下查找隐式实体(隐式方法 隐式类 隐式对象)
2.如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找
类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下:
(1)如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索
(2)如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的
伴生对象和String的伴生对象
(3) 如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索
(4) 如果T是个类型注入S#T,那么S和T都会被搜索