使用 Scala 值 类 定义新的数字类型

Using Scala value classes to define new numeric type

当我第一次听说值 类 时,我想——终于!现在我可以定义我自己的数字类型而无需对象分配!但结果比我想象的要难。

我想定义我自己的小数类型,Dec64 (http://dec64.com/) 或用于快速货币计算的长支持小数。但是,AnyVal 不能扩展 Numeric,因为 Numeric 不是通用特征。我试图跟进 Double 的 Scala 代码,但它相当复杂,有 AnyValCompanionFractionalProxy 和许多 private[scala] 标记的代码,以及非常有用的注释,如 不应在用户代码中扩展。

那么,我该如何正确定义我自己的数值类型,以便与其他 Scala 数字一起使用?

Numeric 是一种类型 class,因此您的 class 不会扩展它。相反,您将为您的类型创建类型 class 的实例。在下面的示例中,为了简单起见,我使用 Int

final class MyNum(val i: Int) extends AnyVal
object MyNum {
  implicit val numeric: Numeric[MyNum] = new Numeric[MyNum] {
    override def plus(x: MyNum, y: MyNum): MyNum = new MyNum(x.i + y.i)
    override def minus(x: MyNum, y: MyNum): MyNum = new MyNum(x.i - y.i)
    override def times(x: MyNum, y: MyNum): MyNum = new MyNum(x.i * y.i)
    override def negate(x: MyNum): MyNum = new MyNum(-x.i)
    override def fromInt(x: Int): MyNum = new MyNum(x)
    override def toInt(x: MyNum): Int = x.i
    override def toLong(x: MyNum): Long = x.i.toLong
    override def toFloat(x: MyNum): Float = x.i.toFloat
    override def toDouble(x: MyNum): Double = x.i.toDouble
    override def compare(x: MyNum, y: MyNum): Int = x.i.compare(y.i)
  }
}

如果您不熟悉 class 类型,我会推荐 Learn You A Haskell For Great Good, particularly its section on type classes。无论如何,这只是一本好书,我强烈建议您通读整本书,以充分理解这些想法的来源。