Class Extension
"+9519760513".exists(_.isDigit)
java.lang.String
并存在exists
方法,为此标准库中在Predef
定义了一个隐式转换,使String
隐式地转换为StringOps
,从而提供更多地操作字符串的方法。
object Predef {
implicit def augmentString(x: String): StringOps = new StringOps(x)
}
Implicit Resolution Rules
Marking Rule
Only definitions marked implicit are available.
object Predef {
implicit def intWrapper(x: Int) = new scala.runtime.RichInt(x)
}
object Predef {
implicit final class any2stringadd[A](private val self: A) extends AnyVal {
def +(other: String): String = String.valueOf(self) + other
}
}
Scope Rule
An inserted implicit conversion must be in scope as a single identifier, or be associated with the source or target type of the conversion.
case class Yard(val amount: Int)
case class Mile(val amount: Int)
mile2yard
可以定义在object Mile
object Mile {
implicit def mile2yard(mile: Mile) = new Yard(10*mile.amount)
}
也可以定义在object Yard
中
object Yard {
implicit def mile2yard(mile: Mile) = new Yard(10*mile.amount)
}
转换为目标类型时,常常发生如下两个场景:
传递参数时,但类型匹配失败;
def accept(yard: Yard) = println(yard.amount + " yards")
accept(Mile(10))
赋值表达式,但类型匹配失败
val yard: Yard = Mile(10)
Other Rules
One-at-a-time Rule: Only one implicit is tried.
Explicits-First Rule: Whenever code type checks as it is written, no implicits are attempted.
No-Ambiguty Rule: An implicit conversion is only inserted if there is no other possible conversion is inserted.
Where implicits are tried?
-
Conversions to an expected type
传递参数时,但类型匹配失败;
赋值表达式,但类型匹配失败
-
Conversions of the receiver of a selection
调用方法,方法不存在
调用方法,方法存在,但参数类型匹配失败
Implicit parameters
Implicit parameters
import scala.math.Ordering
case class Pair[T](first: T, second: T){
def smaller(implicit order: Ordering[T]) =
order.min(first, second)
}
当T
为Int
Pair(1, 2).smaller
编译器实际调用:
Pair(1, 2).smaller(Ordering.Int)
其中Ordering.Int
定义在Ordering
的伴生对象中
object Ordering {
trait IntOrdering extends Ordering[Int] {
def compare(x: Int, y: Int) =
if (x < y) -1
else if (x == y) 0
else 1
}
implicit object Int extends IntOrdering
}
也就是说
implicitly[Ordering[Int]] == Ordering.Int // true
其中,implicitly
为定义在Predef
的一个工具函数,用于提取隐式值
@inline def implicitly[T](implicit e: T) = e
当T
为自定义类型
import scala.math.Ordering
case class Point(x: Int, y: Int)
object Point {
implicit object OrderingPoint extends Ordering[Point] {
def compare(lhs: Point, rhs: Point): Int =
(lhs.x + lhs.y) - (rhs.x + rhs.y)
}
}
Pair(Point(0, 0), Point(1, 1)).smaller
等价于
Pair(Point(0, 0), Point(1, 1)).smaller(Point.OrderingPoint)
也就是说
implicitly[Ordering[Point]] == Point.OrderingPoint
Context Bound
import scala.math.Ordering
case class Pair[T : Ordering](first: T, second: T) {
def smaller(implicit order: Ordering[T]) = order.min(first, second)
}
可以使用implicitly
简化
import scala.math.Ordering
case class Pair[T : Ordering](first: T, second: T) {
def smaller = implicitly[Ordering[T]].min(first, second)
}
可以进一步简化
import scala.math.Ordering
case class Pair[T : Ordering](first: T, second: T) {
def smaller = Ordering[T].min(first, second)
}
Ordering[T]
首先调用了object Ordering
的apply
方法,从而便捷地找到了Order[T]
的隐式值
object Ordering {
def apply[T](implicit ord: Ordering[T]) = ord
}
所以Ordering[T].min
等价于implicitly[Ordering[T]].min
View Bound
import scala.math.Ordered
case class Pair[T](first: T, second: T){
def smaller(implicit order: T => Ordered[T]) = {
if (order(first) < second) first else second
}
}
implicit order: T => Ordered[T]
在smaller
的局部作用域内,即是一个隐式参数,又是一个隐式转换函数。
import scala.math.Ordered
case class Pair[T](first: T, second: T){
def smaller(implicit order: T => Ordered[T]) = {
if (first < second) first else second
}
}
又因为在Predef
预定义了从Int
到RichInt
的隐式转换,而RichInt
是Ordered[Int]
的子类型,所以在Predef
定义的implicit Int => RichInt
的隐式转换函数可作为隐式参数implicit order: T => Ordered[T]
的隐式值。
Pair(1, 2).smaller
等价于
Pair(1, 2).smaller(Predef.intWrapper _)
上述简化的设计,使得隐式参数order
没有必要存在,这样的模式较为常见,可归一为一般模式:View Bound
import scala.math.Ordered
case class Pair[T <% Ordered[T]](first: T, second: T) {
def smaller = if (first < second) first else second
}
需要注意的是:T <% Ordered[T]
表示:T
可以隐式转换为Ordered[T]
;而T <: Ordered[T]
表示:T
是Ordered[T]
的一个子类型。
Upper Bound
import scala.math.Ordered
case class Pair[T <: Comparable[T]](first: T, second: T) {
def smaller = if (first.compareTo(second) < 0) first else second
}
Pair("1", "2").smaller // OK, String is subtype of Comparable[String]
Pair(1, 2).smaller // Compile Error, Int is not subtype of Comparable[Int]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。