什么叫做隐式转换
隐式转换函数是以implicit关键字声明的带有单个参数的函数。这种函数将会自动应用,将值从一种类型转换为另一种类型;在代码重构设计上,可以避免冗余的代码,使得代码非常优雅。
例子1
import java.io.File
import scala.io.Source
/**
* 隐式转换 进来一个普通的出去一个加强的
*/
object Context {
implicit def fileToRichFile(file:File) = new RichFile(file)
}
class RichFile(file:File){
def read():String = Source.fromFile(file).mkString
}
object implicitValue {
def main(args: Array[String]): Unit = {
val file = new File("D:/ssc/wc/1.txt")
import Context.fileToRichFile
val value = file.read()
println(value)
}
}
隐式转换的时机:
- 当方法中的参数的类型与目标类型不一致时。
- 当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换。
- 当对象调用类的方法想被隐式转换成自己想要转换的方法。即上面这种情况。
所以上述总结是隐式转换的时机是在方法被使用之前
使用场景
隐式参数
object ImplicitParam {
def main(args: Array[String]): Unit = {
implicit val name = "tony"
sayHello(25)
}
def sayHello(age:Int)(implicit name:String)
= println("my name is "+ name + "my age is " + age)
}
sayHello函数有两个参数,其中name为隐式参数,在实际调用中不需要显示传入这个参数,但是在作用域范围内必须声明一个String类型的隐式变量,这样在调用的时候,会自动传入这个变量。注意:如果在同一个作用域内定义了两个同类型的隐式变量,则会有冲突。
类型匹配
object ImplicitType {
def main(args: Array[String]): Unit = {
implicit def int2Range(num: Int): Range = 1 to num
val str = spreadNum(5)
println(str)
}
def spreadNum(range: Range) : String = range.mkString(",")
}
上面所示,spreadNum函数签名是个Range类型的参数,但是传入的值是一个Int类型的,所以编译器在作用域内找到了int2Range隐式转换函数,自动将int转换为range对象来适配
类型增强
object ImplicitEnType {
def main(args: Array[String]): Unit = {
implicit def man2SuperMan(man:Man) = new SuperMan(man.name)
val fei = new Man("fei")
fei.fly
}
}
class Man(val name:String)
class SuperMan(val name:String){
def fly = println(name + " can fly")
}
编译器在调用fly方法时,发现Man对象并没有这个函数,然后通过man2SuperMan隐式函数转换成SuperMan对象,进而调用他的fly函数,来实现类型增强功能。
比较器
Ordered和Ordering
Ordered:
class Girl(val name:String,val faceValue:Int,val age:Int){}
- 默认有序,自定义的类继承Ordered接口,在里面重写Compare方法,和Comparable相似
- 通过隐式转换和示图界定
/**
* 视图界定,隐式函数
* viewBound 必须传进一个隐式转换的函数
*/
class MissLeft[T <% Ordered[T]] {
def choose(first:T,sec:T):T ={
if(first > sec) first else sec
}
}
object Context {
/**
* 两种写法 选一种就行
*/
implicit def girl2Ordered(g:Girl) = new Ordered[Girl]{
override def compare(that: Girl): Int = {
g.faceValue - that.faceValue
}
}
implicit val girl2Ordered = (g:Girl) => new Ordered[Girl]{
override def compare(that: Girl): Int = {
g.faceValue - that.faceValue
}
}
}
object MissLeft {
def main(args: Array[String]): Unit = {
import Context._
/**
* Girl <% 表明Girl类的上届是Ordered,
* 即泛型的类型必须是“某种类型”或某种类型的子类
*/
val mL = new MissLeft[Girl]
val g1 = new Girl("林青霞", 97, 29)
val g2 = new Girl("王祖贤", 89, 20)
println(mL.choose(g1, g2).name)
}
}
把隐式转换写到类的前面的原因是,再加载类的时候加载方法,需要把方法进行隐式转换,而不是调用方法时候在进行转换。否则加载不到Ordered[Girl]方法而无法进行比较。
Ordered的隐式转换:源码
object Ordered {
/** Lens from `Ordering[T]` to `Ordered[T]` */
implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] =
new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) }
}
- 通过上下文界定
/**
* 上下文界定
* 必须传进一个隐式转换的值
*/
class MissRight[T:Ordering] {
def choose(first:T,sec:T) : T ={
/**
* 隐式参数
*/
val ord = implicitly[Ordering[T]]
if(ord.gt(first,sec)) first else sec
}
}
object Bound{
/**
* 两种写法选择一种
*/
/*implicit val girl2Ordering = new Ordering[Girl] {
override def compare(x: Girl, y: Girl): Int = {
x.faceValue - y.faceValue
}
}*/
trait girl2Ordering extends Ordering[Girl] {
override def compare(x:Girl,y:Girl) : Int = {
x.faceValue - y.faceValue
}
}
implicit object Girl extends girl2Ordering
}
object MissRight {
def main(args: Array[String]): Unit = {
import Bound._
val mL = new MissLeft[Girl]
val g1 = new Girl("林青霞", 97, 29)
val g2 = new Girl("王祖贤", 89, 20)
println(mL.choose(g1, g2).name)
}
}
Ordering:源码
def apply[T](implicit ord: Ordering[T]) = ord
比较器直接隐式转换
//视图界定 隐式函数
def choose1(first: T, second: T)(implicit ord: T => Ordered[T]): T = {
if (first > second) first else second
}
//上下文界定,隐式值
def choose2(first: T, second: T)(implicit ord: Ordering[T]): T = {
if (ord.gt(first, second)) first else second
}
def choose3(first: T, second: T)(implicit ord: Ordering[T]): T = {
import Ordered.orderingToOrdered
if (first > second) first else second
}