隐式转换系统
隐式转换系统
隐式值和隐式函数
(1)Scala支持两种形式的隐式转换机制---隐式值和隐式视图
隐式值可以用于给方法提供参数
隐式视图是指吧一种类型自动转换成另一种类型,进而适用另一种类型种的属性和方法,从而满足表达式的要求
//作用:如果在隐式作用域里存在这个定义,它会隐式地把原始类型的值转换为增强之后的类型的值(是指在需要的时候)
implicit def myimplict(argName: OriginalType):ViewType
(2)隐式值和隐式视图都采用相同的隐式解析机制,所谓隐式解析是指如果编译器发现代码里缺少部分信息,进而查找缺失信息的过程。隐式解析一般分为两个阶段:在隐式转换的作用域查找中,如果当前作用域没有隐式转换,编译器会自动到相应源或目标类型的伴生对象中查找隐式转换。
(3)在Scala当中,隐式视图即隐式函数的命名一般这样写:前面是转换之前的类型,后面是增强之后的类型,如int2Integer。并且函数的参数一般是转换之前的类的实例,函数的执行体就是创建一个增强类对象.
implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x)
implicit def long2Long(x: Long) = java.lang.Long.valueOf(x)
⑷在隐式视图中,增强类的主构造器的参数类型一般是转换之前的类的类型,并且增强类中含有我们想要的方法。
//隐式值
implicit val str = "scala"
def fun(implicit arg: String) = println("Hello:" + arg)
fun(str)
fun
//隐式视图
def h(arg: String) = println("Hello:" + arg)
implicit def int2String(arg: Int) = arg.toString
h(200)
隐式绑定位置
(1)在应用隐式系统时最重要的一点是确保程序员能够理解一块代码里发生了什么。要做到这点就必须缩小程序员查找可用的隐式值的时候需要看到的代码的范围。隐式绑定可能所处的位置:
- 所有关联类型的伴生对象,包括包对象:即Scala会在关联类的伴生对象中寻找隐式值,这种行为是Scala语言的核心
- Scala.Predef头文件中,每个编译后的Scala文件的开头都有一句
//Predef头文件中包含很多有用的转换方法,比如在Scala.Predef头文件中有个java.lang.Integer =>scala.Int的隐式转换.
implict import scala.Predef._
- 作用域里的所有导入语句
(2) Scala当中如何更好的使用隐式转换:通过伴生类与伴生对象机制,编译器将会自动导入隐式转换,无需用户手动导入隐式转换
class S1 {
def fun(str: String) = println(str)
}
class S2
object S2 {
implicit def s2toS1(arg: S2) = new S1()
}
object Test extends App {
val s2 = new S2
s2.fun("xxxx")
}
隐式转换操作规则
(1)在Scala中,要想使用隐式转换,必须标记为implicit关键字,implict关键字可以用来修饰参数(隐式值与隐式参数)、函数(隐式视图)、类(隐式类)、对象(隐式对象)。
(2)隐式转换在整个作用域中,必须是单一的标识符,进而避免隐式冲突
(3)在隐式转换的作用域查找中,如果当前作用域没有隐式转换,编译器就会自动到相应源或目标类型的伴生对象中查找隐式转换。
(4)Scala中的隐式值、隐式类、隐式对象常放在单例对象object中.
//隐式值与隐式参数
implicit val str = "chen"
def fun(implicit arg: String) = println(arg)
fun
//隐式对象
trait S1{def g(): Unit}
implicit object S2 extends S1{
override def g(): Unit = {println("Hello chen")}
}
def fun2(arg: String)(implicit arg1: S1) = println("xxxxxxxxx")
fun2("Scala")(S2)
fun2("xxxx") //隐式对象作为隐式值
隐式参数
(1)在Scala当中,所谓隐式参数就是在函数或方法中的参数前面加上implicit修饰符,这样的参数叫做隐式参数。
(2)隐式参数提供了很棒的机制,让用户无需指定冗余的参数。
(3)在Scala当中,若在函数的参数前面含有implicit修饰符,编译器就会自动寻找相应的隐式值作为默认值(缺省值)进行传递。
object S1{
implicit val str = "Spark"
}
object Test extends App {
def fun(arg: String)(implicit arg1: String) = println(arg + "\t" + arg1)
fun("java")("scala")
import S1.str
fun("java")
}
隐式类
(1)隐式类就是在普通类的前面加上一个implicit关键字,并修改相应的主构造器,主构造器的参数类型一般是转换之前的类的类型,最后在隐式作用域内导入即可。Scala中的隐式类是对类功能增强的一种形式
(2)Scala中的隐式视图是在转换之前的类的伴生对象中做文章,而Scala中的隐式类是在增强的类中做文章,因为前者不用手动导入,所以Scala中的隐式类相比于隐式视图用的较少.
(3)单例对象中可以构建静态的属性和方法,还可以构建静态的类,若想使用单例对象中的静态类,import导入即可。
object S1{
implicit class MyRichFile(file: java.io.File){
def read(): String = Source.fromFile(file.getPath()).mkString
}
}
object Test extends App {
val file = new File("/xxx")
import S1.MyRichFile
val text = file.read()
}
隐式对象
(1)Scala中的隐式对象就是在object对象前面加上implicit修饰符,隐式对象在某种程度上而言可以作为隐式值进行使用
trait S1{
def fun() = println("liu")
}
implicit object S2 extends S1 {
override def fun() = println("Spark")
}
def g(arg1: String)(implicit arg2: S1) = {
println(arg1)
arg2.fun()
}
g("scala")(new S1 {})
//隐式对象S2在这里将充当隐式值进行使用
g("scala")