【问题标题】:Using Scala value classes to define new numeric type使用 Scala 值类定义新的数值类型
【发布时间】:2015-03-10 10:58:47
【问题描述】:

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

我想定义我自己的 Decimal 类型,Dec64 (http://dec64.com/) 或 long-backed decimal 用于快速货币计算。但是,AnyVals 不能扩展 Numeric,因为 Numeric 不是通用特征。我试图跟进Double 的Scala 代码,但它非常复杂,有AnyValCompanionFractionalProxy 和大量private[scala] 标记代码,以及非常有用的cmets,如不应在用户中扩展代码。

那么,我该如何正确定义我自己的数值类型,它可以与其他 Scala 数字很好地配合使用?

【问题讨论】:

  • 这有点模糊。 “玩得好”是什么意思?答案可能是与其他AnyVals 之间的新类型之间的许多隐式转换。 Numeric[YourType] 的实例也很有用。
  • 这不是你要问的,但我建议看看 Spire,它有许多有用的数字类型的有效实现。如果你想写你自己的,它是基于类型类的,所以更适合与AnyVal 一起使用,而不是基于继承的数字方法。

标签: scala numbers decimal value-class


【解决方案1】:

Numeric 是一个类型类,所以你的类不会扩展它。相反,您将为您的类型创建类型类的实例。在下面的示例中,为了简单起见,我使用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)
  }
}

如果您不熟悉类型类,我会推荐Learn You A Haskell For Great Good,尤其是type classes 部分。无论如何,这只是一本优秀的书,我强烈建议您通读全文以充分了解这些想法的来源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-02
    • 2021-06-22
    • 2012-03-07
    • 1970-01-01
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多