Scala 等价于 Java 的数字
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17999409/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala equivalent of Java's Number
提问by fommil
I am trying to construct a type hierarchy for numerical domain types. e.g. a Yearis an Int(which is a Number), a Percentageis a Double, which is a Number, etc. I need the hierarchy so that I can call toIntor toDoubleon the values.
我正在尝试为数值域类型构建一个类型层次结构。例如 a Yearis an Int(which is a Number), a Percentageis a Double, which is aNumber等。我需要层次结构,以便我可以调用toInt或toDouble值。
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.
但是,原始数字类型的 Scala 类型层次结构除了AnyVal. 这不包含to{Int, Double}我需要的功能。
The closest type I could find is Numeric[T], which seems to exist primarily for some compiler trickery.
我能找到的最接近的类型是Numeric[T],它似乎主要存在于某些编译器技巧中。
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?
在 Java 中,所有的数字都来自Number(包括任意精度的数字)。如何在 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?
这不仅冗长,而且会产生运行时反射成本。有更好的吗?
回答by gzm0
Numeric[T]is exactly what you are looking for. Scala's way to go here is type classes (i.e. a thing like Numeric).
Numeric[T]正是您要寻找的。Scala 的方法是使用类型类(即类似Numeric)。
Instead of
代替
def foo(x: java.lang.Number) = x.doubleValue
write one of
写其中之一
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.Ops
数字操作
Writing calls to the instance of Numericevery time you need an operation can become clumsy when the expression is more complex. To mitigate this, Numericprovides the implicit conversion mkNumericOpswhich augment Twith the common ways of writing mathematical operations (i.e. 1 + 2rather than n.plus(1,2)).
Numeric当表达式更复杂时,在每次需要操作时编写对实例的调用可能会变得笨拙。为了减轻这种情况,Numeric提供了隐式转换mkNumericOps,它增加T了编写数学运算的常用方法(即1 + 2而不是n.plus(1,2))。
In order to use those, just import the members of the implicit Numeric:
为了使用这些,只需导入隐式的成员Numeric:
def foo[T](x: T)(implicit n: Numeric[T]) = {
import n._
x.toDouble
}
Note that due to restrictions on importthe abbreviated syntax for the implicit is hardly desirable here.
请注意,由于对import隐式缩写语法的限制,这里几乎不可取。
Type Classes
类型类
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 implicitexists in scope. If you write
这里会发生什么?如果参数列表被标记为implicit,编译器将自动将所需类型的值放在那里,如果该类型的值恰好有一个被标记为implicit存在于作用域中。如果你写
foo(1.0)
The compiler will automatically change this to
编译器会自动将其更改为
foo(1.0)(Numeric.DoubleIsFractional)
providing the method foowith operations on Double.
提供foo具有操作的方法Double。
The hugeadvantage of this is that you can make types Numericwithout 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.
这样做的巨大优势是您可以在Numeric他们不知道的情况下制作类型。假设您有一个为您提供类型的库MyBigInt。现在假设在 Java 世界中——不幸的是——开发人员没有让它扩展Number。你无能为力。
In Scala, you can just write
在 Scala 中,你可以只写
implicit object MyBigIntIsNumeric extends Numeric[MyBigInt] {
def compare(x: MyBigInt, y: MyBigInt) = ...
// ...
}
and all your code using Numericwill now work with MyBigIntbut you did not have to change the library. So Numericcould even be private to your project and this pattern would still work.
并且您使用的所有代码Numeric现在都可以使用,MyBigInt但您不必更改库。所以Numeric甚至可以是你的项目的私有,这种模式仍然有效。
回答by bourneli
the answer from @gzm0 is a static solution, which the type must be checked in compiling time, I give a dynamic solution which cast the type in runtime,
@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")
}
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")
}
It use case match to choose the correct type in runtime.
它使用案例匹配来在运行时选择正确的类型。

