编写 BigDecimal 计算,就好像它只是 Scala 中常见的四次算术运算

Write BigDecimal calculation as if it's just a usual Four arithmetic operations in Scala

我目前正在研究 Scala,并且对它的出色表现感到惊讶。 我认为最重要的一点是它如何处理 BigDecimal type.Once 定义 BigDecimal 您几乎可以像使用 IntDouble

val foo:BigDecimal = 0.1
println(foo + 0.2) // 0.3

无需使用 .multiply().add(),只需使用 +* 即可处理 BigDecimal 计算(我假设 BigDecimal+/* 虽然最终会在其中调用它们)。即使计算变得复杂,它也很容易阅读,除了你必须将第一个计算值声明为 BigDecimal

println(0.3 * (BigDecimal(0.1) + 0.2))

我的问题是,我怎样才能像这样编写上面的代码?

println(0.3 * (0.1 + 0.2))

我假设这需要覆盖数字类型文字。

提前致谢。

我认为您无法覆盖数字文字。您可以做的是使用字符串插值或向 Double.

添加方法来稍微简化语法
// With string interpolation
implicit class BigDecimalStringContext(private val sc: StringContext) extends AnyVal {
  def d(args: Any*): BigDecimal = {
    val stringRepr = sc.s(args: _*)
    BigDecimal(stringRepr)
  }
}

println(d"0.3" * (d"0.1" + d"0.2"))
println(0.3 * (d"0.1" + 0.2))


// Pimp my library 
implicit class DoubleOps(private val d: Double) extends AnyVal {
  def bd = BigDecimal(d)
}

println(0.3.bd * (0.1.bd + 0.2.bd))
println(0.3 * (0.1.bd + 0.2))

第一种方法比较安全,因为第二种方法试图转换一个Double,因此可能会丢失精度:

scala> 0.123456789012345678901234567890.bd * (0.1.bd + 0.2.bd)
res1: scala.math.BigDecimal = 0.037037036703703704

scala> d"0.123456789012345678901234567890" * (d"0.1" + d"0.2")
res2: scala.math.BigDecimal = 0.0370370367037037036703703703670

不幸的是,Scala 不允许覆盖文字。

你可以在适当的语言中轻松地做一件事,那就是提供你自己的 StringContext for string interpolation:

implicit class BigDecimalStringContext(val sc: StringContext) extends AnyVal {
  def d() = BigDecimal(sc.parts.head)
}

val test = d"0.1"
// => test: scala.math.BigDecimal = 0.1

我相信 Macros 不允许您覆盖文字。

Scala-Virtualized 是 Scala 的一个分支,其中(几乎)所有内容(包括控制结构和对象构造)都转换为方法调用,因此可以重载。不幸的是,几乎一切都不包括重载文字。

但是,您可以使用编译器插件做一些事情。