/**
* 第14章 隐式转换和隐式参数
*/
//########################### 14.1 隐式转换 #################################
/**
* 饮食函数是以implicit关键字声明的带有单个参数的函数
* 这种函数将会自动应用,将值从一种类型转换为另一种类型
*/
class Fraction(val num: Int, val den: Int) {
//定义值的输出
override def toString = num + "/" + den
//定义乘法操作
def *(other: Fraction) = new Fraction(num * other.num, den * other.den)
}
object Fraction {
def apply(num: Int, den: Int) = new Fraction(num, den)
}
//定义 Int->Fraction 隐式转换函数
implicit def int2Fraction(n: Int) = Fraction(n, 1)
/**
* 整数3首先通过int2Fraction函数转换成了Fraction类型,转换函数人和名称都可以,a2b是约定俗成的
* scala中,当一个类型没有那个方法时,scala编译器会去上下文找它对应的隐式转换,
* 如基本类型可以调用对应的rich类型方法,这就是隐式转换的功劳
*/
val result1 = Fraction(3, 1) * Fraction(4, 5)
val result2 = 3 * Fraction(4, 5)
//########################### 14.2 利用隐式转换丰富类库功能 #################################
/**
* 如果需要为一个类增加一个方法,可以通过隐式转换来实现:
* 比如想为File增加一个read方法,可以如下定义:
*/
class File(val str: String)
class RichFile(val from: File) {
def read = "[" + from.str + "]"
}
implicit def file2RichFile(from: File) = new RichFile(from)
val aaa = new Aaa
val contents = new File("aabbcc").read
//########################### 14.3 引入隐式转换 #################################
/**
* 隐式函数位置
* 1.隐式转换一般写在源、目标类型的伴生对象中
* 2.位于当前域
* 3.位于其他类中,需要引入该类,并能直接以该隐式函数名称调用,最好进行引入局部化,如下:
*/
class Aaa {
implicit def file2RichFile(from: File) = new RichFile(from)
}
aaa.file2RichFile(new File("aabbcc")).read
5.toBinaryString
//########################### 14.4 隐式转换规则 #################################
/**
* 隐式转换一般发生在三种情况:
* 1)当表达式的类型和预期类型不一致的时候,编译器会去上下文找隐式转换
* 2)当对象访问一个不存在的成员时,编译器会去找隐式转换,如Int可以调用RichInt的方法
* 3)当对象调用某个方法,而该方法的参数声明和传入参数不匹配时,编译器也会去上下文找参数是否有定义隐式转换
*
* 编译器不会尝试进行隐式转换的三种情况:
* 1)如果有代码能够在不使用隐式转换的前提下编译通过,则不会使用隐式转换
* 2)编译器不会尝试同时执行多个转换,只会找一步转到位的那个隐式转换,没有就编译报错
* 3)存在二义性的转换是错误的,不能定义多个同样的隐式转换,编译器不知道找哪个就会报错
*/
//########################### 14.5 隐式参数 #################################
case class Delimiters(left: String, right: String)
def quote(what: String)(implicit delims: Delimiters) = delims.left + what + delims.right
//原先需要这样:
quote("afdsf")(Delimiters("<", ">"))
object FrenchPunctuation {
implicit val quoteDelimiters = Delimiters("<", ">")
}
//引入隐式转换并局部化
//import FrenchPunctuation._
import FrenchPunctuation.quoteDelimiters
quote("afdsf")
//########################### 14.6 利用隐式参数进行隐式转换 #################################
/**
* 编译时通不过,因为参数类型不能确定是一个带有'<'操作符的类型
*/
//def smaller[T](a: T, b: T) = if (a < b) a else b
/**
* 我们可以通过隐式参数将定义改写如下:
*/
def smaller[T](a: T, b: T)(implicit order: T => Ordered[T]) = if (a < b) a else b
smaller[Int](1, 2)
smaller("a", "b")
//########################### 14.7 上下文界定 #################################
/**
* 视图界定T <% V 要求必须存在一个从T到V的隐式转换.
* 上下文界定的形式为 T:M ,其中M是另一个泛型类,它要求必须存在一个类型为M[T]的隐式值
*/
class Pair5[T: Ordering](val first: T, val second: T) {
def smaller(implicit ord: Ordering[T]) =
if (ord.compare(first, second) < 0) first else second
}