暗黙的型変換とは
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 |