Scala 等价于 Java 的 Number

标签 scala

我正在尝试为数字域类型构建类型层次结构。例如一个 YearInt (这是一个 Number ),一个 PercentageDouble ,这是一个 Number等。我需要层次结构,以便我可以调用 toInttoDouble关于值(value)观。

但是,基本数字类型的 Scala 类型层次结构除了 AnyVal 之外没有共同祖先。 .这不包含 to{Int, Double}我需要的功能。

我能找到的最接近的类型是 Numeric[T] ,这似乎主要是为了一些编译器的诡计而存在的。

在 Java 中,所有来自 Number 的数字(包括任意精度的)。 如何在 Scala 中定义一个满足数字类型对象的接口(interface)?

我目前正在用鸭子打字来破解它:

Any {
  def toInt: Int
  def toDouble: Double
}

这不仅冗长,而且会产生运行时反射成本。有更好的吗?

最佳答案

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) )。

为了使用这些,只需导入隐式 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)

提供方法fooDouble 进行操作.

这样做的巨大优势是您可以创建类型 Numeric在他们不知情的情况下。假设你有一个库,它给你一个类型 MyBigInt .现在假设在 Java 世界中 - 不幸的是 - 开发人员没有让它扩展 Number .你无能为力。

在 Scala 中,你可以只写
implicit object MyBigIntIsNumeric extends Numeric[MyBigInt] {
   def compare(x: MyBigInt, y: MyBigInt) = ...
   // ...
}

以及所有使用 Numeric 的代码现在将与 MyBigInt 一起使用但是 您不必更改库 .所以Numeric甚至可以是您的项目私有(private)的,并且这种模式仍然有效。

关于Scala 等价于 Java 的 Number,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17999409/

相关文章:

scala - 如何为scala子类型实现流畅的接口(interface)?

scala - play 框架将子类传递给 scala 模板

.net - 有没有办法在 Visual Studio 中进行 Scala 编程?

scala - 余积的类型类推导?

scala - 如何在 ScalaTest 中使测试失败并打印堆栈跟踪?

scala - Scala 2.10中的新行为

multithreading - akka actor 如何在底层线程上实现?

scala - 为什么 sbt 程序集失败并显示 "Not a valid command: assembly"?

java - 将 Scala 与 Apache Camel 结合使用是否存在已知问题?

eclipse - Scala Eclipse IDE不会通过Gradle引入外部依赖关系