暗黙的型変換 implicit

暗黙的型変換とは

x + y が型チェックを通らない場合、Scalaコンパイラーは x に何らかの型変換を行い、型チェックが通る状態としてコンパイルを試みる。この型変換は、implicitによって定義された変換メソッドが存在する場合に行われる。
つまり、implicitによって変換メソッドが定義されている場合、該当する型変換が暗黙的に行われることになる。

implicitの例

以下のようなBookクラスを考える

class Book(t : String) {
  def title = t
}

以下のように使うと「scala」と出力される。

object Main {
  def main(args : Array[String]) : Unit = {
    var book = new Book("scala")
    println(book.title)
  }
}

では、以下のようにすると、

object Main {
  def main(args : Array[String]) : Unit = {
    var book = new Book("scala")
    println(book.title)
    println(book + 2)   // コンパイルエラー
  }
}

bookには+メソッドが無いのでもちろんコンパイルエラーとなる。

そこで、BookからInt型への暗黙的型変換を定義してみる。

object Main {
  def main(args : Array[String]) : Unit = {
    var book = new Book("scala")
    println(book.title)
    println(book + 2)
  }
  implicit def book2Int(x:Book):Int = x.title.length
}

型変換として、Book型からInt型への変換は、Bookのtitleの文字数を返却する、変換メソッドとして定義している。

実行すると、

scala
7

リッチラッパー

Scalaでは以下のような記述ができる。

    println(0 max 5)    // 5
    println(-3.4 abs)   // 3.4

Int には max メソッドが定義されておらず、Double は abs メソッドが定義されていないが、前述の記述ができるのは、Scala ライブラリ中の Predef にて implicit 定義が実装されているからである。
Predef 中の Int についての implicit 定義は以下のようになっている。

  implicit def intWrapper(x: Int) = new runtime.RichInt(x)

Intに対して型チェックが通らない場合は、RichIntというラッパークラスへの暗黙的な型変換が行われる。
RichInt内では、maxなどのメソッド定義がされており、これにより前述の出力結果が得られている。

これらのリッチラッパーは、基本型のクラスすべてに用意されている。

基本型 対応するリッチラッパー
Byte runtime.RichByte
Short runtime.RichShort
Int runtime.RichInt
Char runtime.RichChar
Long runtime.RichLong
Float runtime.RichFloat
Double runtime.RichDouble
Boolean runtime.RichBoolean

その他にも以下のようなラッパーも提供されている

クラス 対応するリッチラッパー
String runtime.RichString
StringBuilder runtime.RichStringBuilder
Throwable runtime.RichException