Numeric[T]
まさにあなたが探しているものです。Scala がここに行く方法は、型クラス (つまり のようなものNumeric
) です。
それ以外の
def foo(x: java.lang.Number) = x.doubleValue
のいずれかを書きます
def foo[T](x: T)(implicit n: Numeric[T]) = n.toDouble(x)
def foo[T : Numeric](x: T) = implicitly[Numeric[T]].toDouble(x)
2 番目は (ほとんど) シンタックス シュガーにすぎません。
Numeric.Ops
Numeric
式がより複雑になると、操作が必要になるたびに のインスタンスへの呼び出しを記述するのが面倒になる可能性があります。これを軽減するために、数学演算を記述する一般的な方法 (つまりではなく)を拡張するNumeric
暗黙的な変換を提供します。mkNumericOps
T
1 + 2
n.plus(1,2)
それらを使用するには、 Implicit のメンバーをインポートするだけNumeric
です:
def foo[T](x: T)(implicit n: Numeric[T]) = {
import n._
x.toDouble
}
import
ここでは、暗黙の省略構文の制限により、ほとんど望ましくないことに注意してください。
型クラス
そこで何が起こるの?引数リストが としてマークされている場合、スコープ内に存在するimplicit
とマークされている型の値が 1 つだけあれば、コンパイラは必要な型の値をそこに自動的に配置します。implicit
あなたが書くなら
foo(1.0)
コンパイラはこれを自動的に次のように変更します。
foo(1.0)(Numeric.DoubleIsFractional)
メソッドfoo
に に対する操作を提供しDouble
ます。
これの大きな利点は、Numeric
知らないうちに型を作成できることです。type を提供するライブラリがあるとしますMyBigInt
。ここで、Java の世界で (残念ながら) 開発者が Java を拡張しなかったとしますNumber
。あなたにできることは何もありません。
Scalaでは、次のように書くことができます
implicit object MyBigIntIsNumeric extends Numeric[MyBigInt] {
def compare(x: MyBigInt, y: MyBigInt) = ...
// ...
}
を使用しているすべてのコードNumeric
が動作するようになりましMyBigInt
たが、ライブラリを変更する必要はありませんでした。そのNumeric
ため、プロジェクトに対して非公開にすることもでき、このパターンは引き続き機能します。