Scala 隐式转换和具有值 类 的 mkNumericOps
Scala implicit conversions and mkNumericOps with value classes
我正在尝试将数字运算添加到我定义的名为 Quantity
的值 class 中。我正在使用的代码如下...
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
特征为值 class 创建数值运算是非常标准的。我做错了什么?
问题是,虽然您提供了支持丰富操作的转换,但它的优先级低于 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
Imported implicits 将始终优先于伴随对象中定义的 implicits,并且 Predef
被隐式导入到所有源文件中(除非您启用了 -Yno-predef
,我强烈推荐,至少对于库代码)。
除非您愿意关闭 Predef
,否则解决此问题的唯一方法是导入转换(即使您可以关闭 Predef
,您的用户也可能无法或愿意)。
作为旁注,您可以通过使用 Numeric
作为类型 class:
使这段代码更加地道
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
类型 class 的隐式实例。现在您需要导入 any 使用 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 用户更可能知道的标准导入,而不是您必须单独解释的自定义内容。
我正在尝试将数字运算添加到我定义的名为 Quantity
的值 class 中。我正在使用的代码如下...
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
特征为值 class 创建数值运算是非常标准的。我做错了什么?
问题是,虽然您提供了支持丰富操作的转换,但它的优先级低于 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
Imported implicits 将始终优先于伴随对象中定义的 implicits,并且 Predef
被隐式导入到所有源文件中(除非您启用了 -Yno-predef
,我强烈推荐,至少对于库代码)。
除非您愿意关闭 Predef
,否则解决此问题的唯一方法是导入转换(即使您可以关闭 Predef
,您的用户也可能无法或愿意)。
作为旁注,您可以通过使用 Numeric
作为类型 class:
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
类型 class 的隐式实例。现在您需要导入 any 使用 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 用户更可能知道的标准导入,而不是您必须单独解释的自定义内容。