Scala 等价于 Java 的数字 [英] Scala equivalent of Java's Number

查看:37
本文介绍了Scala 等价于 Java 的数字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为数值域类型构建类型层次结构.例如YearInt(这是一个 Number),PercentageDoublecode>,它是一个 Number 等.我需要层次结构,以便我可以对值调用 toInttoDouble.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆