30

数値ドメイン型の型階層を構築しようとしています。たとえば、 aYearは an Int( a Number)、 aPercentageは a Double、 aなどです。値に対してorNumberを呼び出せるように階層が必要です。toInttoDouble

ただし、プリミティブ数値型の Scala 型階層には、 以外に共通の祖先はありませんAnyValto{Int, Double}これには必要な機能が含まれていません。

私が見つけた最も近い型は です。これはNumeric[T]、主にコンパイラのトリックのために存在しているようです。

NumberJava では、 (任意精度のものを含む)から派生したすべての数値。Scala でオブジェクトの数値型に対応するインターフェイスをどのように定義しますか?

私は現在、ダックタイピングでハッキングしています:

Any {
  def toInt: Int
  def toDouble: Double
}

これは時間がかかるだけでなく、実行時のリフレクション コストが発生します。もっと良いものはありますか?

4

2 に答える 2

60

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暗黙的な変換を提供します。mkNumericOpsT1 + 2n.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ため、プロジェクトに対して非公開にすることもでき、このパターンは引き続き機能します。

于 2013-08-01T16:37:47.050 に答える
-1

@gzm0 からの回答は静的ソリューションであり、コンパイル時に型をチェックする必要があります。実行時に型をキャストする動的ソリューションを提供します。

def toDoubleDynamic(x: Any) = x match { case s: String => s.toDouble case jn: java.lang.Number => jn.doubleValue() case _ => throw new ClassCastException("cannot cast to double") }

大文字と小文字の一致を使用して、実行時に正しい型を選択します。

于 2016-04-22T11:03:23.323 に答える