(Scala 14) 隐式转换和隐式参数

/**
  * 第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
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值