Implicit Conversion や Implicit Parameter が探索される範囲には、次のような範囲がある。
- ローカルで定義されたもの
- import で指定されたもの
- スーパークラスで定義されたもの
- コンパニオンオブジェクトで定義されたもの
ここでは、コンパニオンオブジェクトに Implicit を定義するパターンを見てみる。
新しく Rational (有理数)型を定義するとして、次のように定義する。ここでは Rational.scala ファイルに書いた。
trait Additive[A] { def plus(a: A, b: A): A def zero: A } case class Rational(num: Int, den: Int) object Rational { implicit object RationaAdditive extends Additive[Rational] { def plus(a: Rational, b: Rational): Rational = { if (a == zero) { b } else if (b == zero) { a } else { Rational(a.num * b.den + b.num * a.den, a.den * b.den) } } def zero: Rational = Rational(0, 0) } }
同じディレクトリで sbt console を起動すると自動的に読み込まれる。
で、sum メソッドを定義。なんでファイルに書かないかというと、クラスやトレイトに属さないメソッドはファイルには書けない(たぶん)から。
scala> def sum[A](lst: List[A])(implicit m: Additive[A]) = lst.foldLeft(m.zero)((x, y) => m.plus(x, y)) sum: [A](lst: List[A])(implicit m: Additive[A])A
さて、これで準備は完了。有理数の合計を求めてみる。
scala> sum(List(Rational(1, 2), Rational(1, 3))) res0: Rational = Rational(5,6)
ちゃんと計算できた。
コンパニオンオブジェクトに Implicit を定義しておくのはわかりやすいかもしれないな。覚えておこう。