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
甚至可以是您的项目私有的,并且这种模式仍然有效。