Scala 等价于 Java 的数字 [英] Scala equivalent of Java's Number
问题描述
我正在尝试为数值域类型构建类型层次结构.例如Year
是 Int
(这是一个 Number
),Percentage
是 Double
code>,它是一个 Number
等.我需要层次结构,以便我可以对值调用 toInt
或 toDouble
.
I am trying to construct a type hierarchy for numerical domain types. e.g. a Year
is an Int
(which is a Number
), a Percentage
is a Double
, which is a Number
, etc. I need the hierarchy so that I can call toInt
or toDouble
on the values.
然而,除了 AnyVal
之外,原始数字类型的 Scala 类型层次结构没有共同的祖先.这不包含我需要的 to{Int, Double}
函数.
However, the Scala type hierarchy for the primitive numeric types has no common ancestor except AnyVal
. This does not contain the to{Int, Double}
functions that I need.
我能找到的最接近的类型是 Numeric[T]
,它似乎主要用于一些编译器技巧.
The closest type I could find is Numeric[T]
, which seems to exist primarily for some compiler trickery.
在 Java 中,所有从 Number
派生的数字(包括任意精度的数字).如何在 Scala 中定义一个满足数值类型对象的接口?
In Java, all the numbers derived from Number
(including the arbitrary precision ones). How does one define an interface that caters for numerical types of object in Scala?
我目前正在用鸭子打字来破解它:
I'm currently hacking it with duck typing:
Any {
def toInt: Int
def toDouble: Double
}
这不仅冗长,而且会产生运行时反射成本.有没有更好的?
which is not only long-winded, but incurs runtime reflection costs. Is there anything better?
推荐答案
Numeric[T]
正是您正在寻找的.Scala 在这里的方法是类型类(即像 Numeric
这样的东西).
Numeric[T]
is exactly what you are looking for. Scala's way to go here is type classes (i.e. a thing like 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)
其中第二个(几乎)只是语法糖.
where the second is (almost) nothing but syntactic sugar.
当表达式更复杂时,每次需要操作时写入对 Numeric
实例的调用可能会变得笨拙.为了缓解这种情况,Numeric
提供了隐式转换 mkNumericOps
,它用编写数学运算的常用方法(即 1 + 2
而不是 n.plus(1,2)
).
Writing calls to the instance of Numeric
every time you need an operation can become clumsy when the expression is more complex. To mitigate this, Numeric
provides the implicit conversion mkNumericOps
which augment T
with the common ways of writing mathematical operations (i.e. 1 + 2
rather than n.plus(1,2)
).
为了使用这些,只需导入隐式Numeric
的成员:
In order to use those, just import the members of the implicit Numeric
:
def foo[T](x: T)(implicit n: Numeric[T]) = {
import n._
x.toDouble
}
请注意,由于对 import
的限制,隐式的缩写语法在这里几乎是不可取的.
Note that due to restrictions on import
the abbreviated syntax for the implicit is hardly desirable here.
这里发生了什么?如果一个参数列表被标记为 implicit
,编译器会自动将一个所需类型的值放在那里,如果该类型的一个值被标记为 implicit
存在于作用域中.如果你写
What happens here? If an argument list is marked as implicit
, the compiler will automatically put a value of the required type there iff exactly one value of that type that is marked as implicit
exists in scope. If you write
foo(1.0)
编译器会自动把它改成
foo(1.0)(Numeric.DoubleIsFractional)
为方法 foo
提供对 Double
的操作.
providing the method foo
with operations on Double
.
巨大的优点是你可以在他们不知道的情况下创建类型Numeric
.假设您有一个为您提供类型 MyBigInt
的库.现在假设在 Java 世界 - 不幸的是 - 开发人员没有让它扩展 Number
.你无能为力.
The huge advantage of this is that you can make types Numeric
without them knowing. Suppose you have a library that gives you a type MyBigInt
. Now suppose that in the Java world - unfortunately - the developers did not make it extend Number
. There is nothing you can do.
在 Scala 中,您只需编写
In Scala, you can just write
implicit object MyBigIntIsNumeric extends Numeric[MyBigInt] {
def compare(x: MyBigInt, y: MyBigInt) = ...
// ...
}
并且您使用 Numeric
的所有代码现在都可以与 MyBigInt
一起使用,但您不必更改库.所以 Numeric
甚至可以是你的项目的私有,这种模式仍然有效.
and all your code using Numeric
will now work with MyBigInt
but you did not have to change the library. So Numeric
could even be private to your project and this pattern would still work.
这篇关于Scala 等价于 Java 的数字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!