隱式類(Implicit Classes)

Josh Suereth

介紹

Scala 2.10引入了一種叫做隱式類的新特性。隱式類指的是用implicit關鍵字修飾的類。在對應的作用域內,帶有這個關鍵字的類的主構造函數可用於隱式轉換。

隱式類型是在SIP-13中提出的。

用法

創建隱式類時,只需要在對應的類前加上implicit關鍵字。比如:

object Helpers {
  implicit class IntWithTimes(x: Int) {
    def times[A](/DOC_Scala/chinese_scala_offical_document/file/f: => A): Unit = {
      def loop(current: Int): Unit =
        if(current > 0) {
          f
          loop(current - 1)
        }
      loop(x)
    }
  }
}

這個例子創建了一個名為IntWithTimes的隱式類。這個類包含一個int值和一個名為times的方法。要使用這個類,只需將其導入作用域內並調用times方法。比如:

scala> import Helpers._
import Helpers._

scala> 5 times println("HI")
HI
HI
HI
HI
HI

使用隱式類時,類名必須在當前作用域內可見且無歧義,這一要求與隱式值等其他隱式類型轉換方式類似。

限制條件

隱式類有以下限制條件:

  1. 只能在別的trait/類/對象內部定義。
object Helpers {
       implicit class RichInt(x: Int) // 正確!
    }
    implicit class RichDouble(x: Double) // 錯誤!
  1. 構造函數只能攜帶一個非隱式參數。implicit class RichDate(date: java.util.Date) // 正確! implicit class Indexer[T](collecton: Seq[T], index: Int) // 錯誤! implicit class Indexer[T](collecton: Seq[T])(implicit index: Index) // 正確!

雖然我們可以創建帶有多個非隱式參數的隱式類,但這些類無法用於隱式轉換。

  1. 在同一作用域內,不能有任何方法、成員或對象與隱式類同名。

注意:這意味着隱式類不能是case class。

object Bar
implicit class Bar(x: Int) // 錯誤!

val x = 5
implicit class x(y: Int) // 錯誤!

implicit case class Baz(x: Int) // 錯誤!