"+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]