1、隐式转换java
隐式转换函数: 指的是以implicit关键字声明的带有单个参数的函数。这样的函数将被自动应用,将值从一种类型转换为另外一种类型。git
例子:
github
package com.test /** * Created by Edward on 2018/2/7. */ class Fraction(val n : Int, val d : Int){ def * (other:Fraction) = Fraction(n*other.n,d*other.d) // 定义Fraction * Fraction } object Fraction{ def apply(n : Int, d : Int)= new Fraction(n, d) } object ImplicitFunc { //声明须要 implicit 关键字,只有一个参数,自动将参数的类型转换为函数实现的其余类型 implicit def int2Fraction(n: Int) = Fraction(n, 1) } object Chapter21 { def main(args: Array[String]) { import com.test.ImplicitFunc._ //须要 import 函数所在具体的位置 val i = 3 * Fraction(3,2) //Int类型不能* Fraction类型, Int类型自动转换为Fraction类型 println(i.n,i.d) } }
结果:app
(9,2)
2、利用隐式转换丰富现有类库的功能函数
package com.test import java.io.File import scala.io.Source /** * Created by Edward on 2018/2/7. */ class RichFile(val from:File){ def read = Source.fromFile(from.getPath).mkString } object Chapter21 { implicit def file2RichFile (from :File) = new RichFile(from) //隐式转换将原来的File类型转换到这个新的类型;新的类型有read方法。 def main(args: Array[String]) { val contents = new File("file/wordcount.txt").read println(contents) } }
结果:oop
hello world
good morning
3、引入隐式转换this
Scala会考虑以下的隐式转换函数:spa
1.位于源或目标类型的伴生对象中的隐式函数scala
2.位于当前做用域能够以单个标识符指代的隐式函数code
object Fraction{ def apply(n : Int, d : Int)= new Fraction(n, d) implicit def int2Fraction(n: Int) = Fraction(n, 1) //隐式转换在伴生对象中 }
使用import引入隐式函数 import com.test.Fraction._
4、隐式转换规则
隐式转换在如下三种状况下发生:
一、当表达式的类型与预期的类型不一样时
sqrt(Fraction(1,4))
sqrt预期是Double, 将调用fraction2Double
二、当对象访问一个不存在的成员时
new File("README").read
File没有read方法,将调用file2RichFile
三、当对象调用某个方法,而该方法的参数声明与传入参数不匹配时
3 * Fraction(4,5)
Int的*方法不接受Fraction做为参数,将调用int2Fraction
不会发生隐式转换的状况:
一、若是代码在不使用隐式转换的前提下经过编译,则不会使用隐式转换
如: a * b 可以编译,那么编译器不会尝试 a * convert(b) 或 convert(a) * b;
二、编译器不会同时执行多个转换
如: convert(convert(a))*b;
三、存在二义性的转换是个错误
如:convert1(a) * b 和 convert2(a) * b;
package com.test import java.io.File import scala.io.Source /** * Created by Edward on 2018/2/7. */ class Fraction(val n : Int, val d : Int){ def * (other:Fraction) = Fraction(n*other.n,d*other.d) // 定义Fraction * Fraction } object Fraction{ def apply(n : Int, d : Int)= new Fraction(n, d) implicit def int2Fraction(n: Int) = Fraction(n, 1) implicit def fraction2Double(f:Fraction) = f.n * 1.0 / f.d } object Chapter21 { def main(args: Array[String]) { import com.chinahadoop.test.Fraction._ //须要 import 隐式函数所在具体的位置 val i = Fraction(3,2) * 3 //转换 Int 为 Fraction 调用 int2Fraction println(i) val i1 = 3 * Fraction(3,2) //转换 Fraction 为 Int 调用 fraction2Double println(i1) } }
结果:
com.test.Fraction@6879c0f4
4.5
两个类型,优先转换方法*后面的类型
若是注释掉 以下代码,则须要转换*前面的类型
//implicit def int2Fraction(n: Int) = Fraction(n, 1)
结果为:
4.5 4.5
这里不存在二义性,这里隐式转换是针对不一样的类型,存在二义性是针对相同的类型有不一样的转换方法。
5、隐式参数
object Chapter21 { case class Delimiters(left : String, right : String) implicit val quoteDelimiter = Delimiters("<<",">>") def main(args: Array[String]) { def quote(what : String)(implicit delimiter : Delimiters) = delimiter.left + what + delimiter.right println(quote("Hello")) } }
输出:
<<Hello>>
对于给定的数据类型,只有一个隐式的值
def quota(what: String)(implicit left : String, right : String) // 不正确
6、利用隐式参数进行隐式转换
def smaller[T](a : T, b : T) = if (a < b) a else b
这种实现方式是不对的,泛型T中不肯定 < 方法。
使用 T到Ordered[T]的隐式转换, Ordered[T] 有接收参数为T的<操做符。
def smaller[T](a : T, b : T)(implicit order:T => Ordered[T]) = if (order(a) < b) a else b println(smaller(10,34))
理解
implicit order:T => Ordered[T]
Ordered对象提供了从T到Ordered[T]的隐式转换(隐式参数为Ordering[T])
源码:https://github.com/scala/scala/blob/v2.12.4/src/library/scala/math/Ordered.scala#L1
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) } }
若是使用自定义类型,咱们能够实现Ordered[Fraction]特质的compare方法。
class Fraction (val n : Int, val d : Int) extends Ordered[Fraction]{ def * (other:Fraction) = Fraction(n*other.n,d*other.d) // 定义Fraction * Fraction def compare(that:Fraction) = this.n - that.n } def smaller[T](a : T, b : T)(implicit order:T => Ordered[T]) = if (a < b) a else b println(smaller(Fraction(3,6), Fraction(4,9)))
order不只是一个隐式参数,仍是一个隐式转换。
7、上下文界定
Ordered 、Ordering
Scala提供两个特质(trait)Ordered与Ordering用于比较。其中,Ordered混入(mix)Java的Comparable接口,而Ordering则混入Comparator接口。
在Java中:
实现Comparable接口的类,其对象具备了可比较性;
实现Comparator接口的类,则提供一个外部比较器,用于比较两个对象。
Ordered与Ordering的区别与之相相似:Ordered特质定义了相同类型间的比较方式,但这种内部比较方式是单一的;Ordering则是提供比较器模板,能够自定义多种比较方式。