"+9519760513".exists(_.isDigit)
java.lang.String
并存在exists
方法,为此标准库中在Predef
定义了一个隐式转换,使String
隐式地转换为StringOps
,从而提供更多地操做字符串的方法。java
object Predef { implicit def augmentString(x: String): StringOps = new StringOps(x) }
Only definitions marked implicit are available.git
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 } }
An inserted implicit conversion must be in scope as a single identifier, or be associated with the source or target type of the conversion.app
case class Yard(val amount: Int) case class Mile(val amount: Int)
mile2yard
能够定义在object Mile
ide
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) }
转换为目标类型时,经常发生以下两个场景:工具
传递参数时,但类型匹配失败;scala
def accept(yard: Yard) = println(yard.amount + " yards") accept(Mile(10))
赋值表达式,但类型匹配失败设计
val yard: Yard = Mile(10)
One-at-a-time Rule: Only one implicit is tried.code
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.
Conversions to an expected type
传递参数时,但类型匹配失败;
赋值表达式,但类型匹配失败
Conversions of the receiver of a selection
调用方法,方法不存在
调用方法,方法存在,但参数类型匹配失败
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
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
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]
的一个子类型。
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]