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.Orderingcase 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.Orderingcase 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.Orderingcase class Pair[T : Ordering](first: T, second: T) { def smaller(implicit order: Ordering[T]) = order.min(first, second)}
可以使用implicitly
简化
import scala.math.Orderingcase class Pair[T : Ordering](first: T, second: T) { def smaller = implicitly[Ordering[T]].min(first, second)}
可以进一步简化
import scala.math.Orderingcase 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.Orderedcase 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.Orderedcase 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.Orderedcase 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.Orderedcase 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]