我正在尝试将数值运算添加到我定义的名为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)
}
编译器似乎无法找到数字+
运算符的隐式转换。想法?
我认为使用隐式转换和Numeric
特征为值类创建数值运算是非常标准的。我做错了什么?
答案 0 :(得分:4)
问题在于,虽然您提供了支持丰富操作的转化,但其优先级低于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
并明确使用其ops实例,而只是在伴随对象中提供Numeric
类型类的隐式实例。现在您需要导入任何使用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用户更有可能了解的标准导入,而不是您必须单独解释的自定义内容。