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)
第二个(几乎)只是语法糖。
数值运算
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,编译器将自动将所需类型的值放在那里,只要该类型的值恰好implicit存在于范围内。如果你写
foo(1.0)
编译器会自动将其更改为
foo(1.0)(Numeric.DoubleIsFractional)
为方法提供对foo的操作Double。
这样做的巨大优势是您可以在Numeric他们不知道的情况下制作类型。假设您有一个为您提供 type 的库MyBigInt。现在假设在 Java 世界中——不幸的是——开发人员没有扩展它Number。你无能为力。
在 Scala 中,你可以只写
implicit object MyBigIntIsNumeric extends Numeric[MyBigInt] {
def compare(x: MyBigInt, y: MyBigInt) = ...
// ...
}
并且您使用的所有代码Numeric现在都可以使用,MyBigInt但您不必更改库。所以Numeric甚至可以是您的项目私有的,并且这种模式仍然有效。