3

我正在尝试将数值运算添加到我定义的名为Quantity. 我正在使用的代码如下...

import scala.language.implicitConversions

case class Quantity(value: Double) extends AnyVal

object Quantity {
  implicit def mkNumericOps(lhs: Quantity): QuantityIsNumeric.Ops = QuantityIsNumeric.mkNumericOps(lhs)
}

object QuantityIsNumeric extends Numeric[Quantity] {

  def plus(x: Quantity, y: Quantity): Quantity = Quantity(x.value + y.value)

  def minus(x: Quantity, y: Quantity): Quantity = Quantity(x.value - y.value)

  def times(x: Quantity, y: Quantity): Quantity = Quantity(x.value * y.value)

  def negate(x: Quantity): Quantity = Quantity(-x.value)

  def fromInt(x: Int): Quantity = Quantity(x.toDouble)

  def toInt(x: Quantity): Int = x.value.toInt

  def toLong(x: Quantity): Long = x.value.toLong

  def toFloat(x: Quantity): Float = x.value.toFloat

  def toDouble(x: Quantity): Double = x.value

  def compare(x: Quantity, y: Quantity): Int = x.value compare y.value
}

我使用此代码如下...

class SortedAskOrders[T <: Tradable] private(orders: immutable.TreeSet[LimitAskOrder[T]], val numberUnits: Quantity) {

  def + (order: LimitAskOrder[T]): SortedAskOrders[T] = {
    new SortedAskOrders(orders + order, numberUnits + order.quantity)
  }

  def - (order: LimitAskOrder[T]): SortedAskOrders[T] = {
    new SortedAskOrders(orders - order, numberUnits - order.quantity)
  }

  def head: LimitAskOrder[T] = orders.head
  def tail: SortedAskOrders[T] = new SortedAskOrders(orders.tail, numberUnits - head.quantity)
}

...当我尝试编译此代码时,我收到以下错误..

Error:(29, 63) type mismatch;
 found   : org.economicsl.auctions.Quantity
 required: String
      new SortedAskOrders(orders + order, numberUnits + order.quantity)

以下+显式使用隐式转换的方法实现(我认为应该已经在范围内!)有效。

def + (order: LimitAskOrder[T]): SortedAskOrders[T] = {
  new SortedAskOrders(orders + order, Quantity.mkNumericOps(numberUnits) + order.quantity)
}

编译器似乎无法找到数字+运算符的隐式转换。想法?

我认为使用隐式转换和Numerictrait 为值类创建数字运算是非常标准的。我究竟做错了什么?

4

1 回答 1

3

问题是,虽然您提供了支持丰富操作的转换,但它的优先级低于scala.Predef.any2stringadd. any2stringadd您可以通过使用此处不适用的实现来隐藏名称来确认这一点:

scala> implicit def any2stringadd(i: Int): Int = i
any2stringadd: (i: Int)Int

scala> def add(a: Quantity, b: Quantity): Quantity = a + b
add: (a: Quantity, b: Quantity)Quantity

导入的隐式将始终优先于伴随对象中定义的隐式,并且Predef隐式导入到所有源文件中(除非您已启用-Yno-predef,我强烈推荐,至少对于库代码)。

除非您愿意关闭Predef,否则解决此问题的唯一方法是导入转换(即使您可以关闭Predef,您的用户也可能无法或不愿意)。

Numeric附带说明一下,您可以通过将其用作类型类来使此代码更加惯用:

case class Quantity(value: Double) extends AnyVal

object Quantity {
  implicit val quantityNumeric: Numeric[Quantity] = new Numeric[Quantity] {
    def plus(x: Quantity, y: Quantity): Quantity = Quantity(x.value + y.value)
    def minus(x: Quantity, y: Quantity): Quantity = Quantity(x.value - y.value)
    def times(x: Quantity, y: Quantity): Quantity = Quantity(x.value * y.value)
    def negate(x: Quantity): Quantity = Quantity(-x.value)
    def fromInt(x: Int): Quantity = Quantity(x.toDouble)
    def toInt(x: Quantity): Int = x.value.toInt
    def toLong(x: Quantity): Long = x.value.toLong
    def toFloat(x: Quantity): Float = x.value.toFloat
    def toDouble(x: Quantity): Double = x.value
    def compare(x: Quantity, y: Quantity): Int = x.value compare y.value
  }
}

即,您只需在伴生对象中提供类型类Numeric的隐式实例,而不是让对象实例化并显式使用其操作实例。Numeric现在你需要一个 import 来使用ops 语法方法:

scala> import Numeric.Implicits._
import Numeric.Implicits._

scala> def add(a: Quantity, b: Quantity): Quantity = a + b
add: (a: Quantity, b: Quantity)Quantity

但这是其他 Scala 用户更可能知道的标准导入,而不是您必须单独解释的自定义内容。

于 2017-03-14T14:48:07.410 回答