我有以下通用的Interval类(由用户soc为我制定):
case class Interval[T](from: T, to: T)(implicit num: Numeric[T]) {
import num.mkNumericOps // allows us to write from.toDouble and to.toDouble
def mid: Double = (from.toDouble + to.toDouble) / 2.0
}
典型用例:Interval [Double]或Interval [Int]。要添加二进制 union 和交集运算符,我在伴随对象中使用了与(implicit num: Numeric[T])
类似的模式:
object Interval {
def union[T](interval1: Interval[T], interval2: Interval[T])(implicit num: Numeric[T]) = {
import num.mkOrderingOps // allows interval1.from min
Interval[T](interval1.from min interval2.from, interval1.to max interval2.to)
}
def intersect[T](interval1: Interval[T], interval2: Interval[T])(implicit num: Numeric[T]) = {
import num.mkOrderingOps
Interval[T](interval1.from max interval2.from, interval1.to min interval2.to)
}
}
在两种方法中复制(implicit num: Numeric[T])
和import num.mkOrderingOps
都是丑陋的样板。在Interval对象本身的层次上,有一些方法可以做到这一点吗?
答案 0 :(得分:8)
是的。
首先进口。您可以在Interval的范围内导入Ordering.Implicits._。
object Interval {
import Ordering.Implicits._
def union[T](....)(implicit num: Numeric[T]) = {
// do not import num.mkOrderingOps
...
}
...
}
有了这些含义,当它找到一个排序操作时,它会在操作发生的范围内寻找隐式的Ordering(Numeric is a Ordering)。在每个例程中,恰好有一个隐含的范围。如果您也需要算术运算,也可以导入Numeric.Implicits ._
现在有了隐含的参数。语言中有一个快捷方式,称为上下文绑定:
你可以写def f[T: X](args)
而不是def f[T](args)(implicit someName: X[T])
不同之处在于你没有带有上下文绑定的隐含名称(你可以使用implictly [T]但是这几乎不会更短。幸运的是,你不再需要使用import Ordering的名字了。 Implicits ._
所以
object Interval {
import Ordering.Implicits._
// also import Numeric.Implicits._ if you need +,-,*,/ ...
def union[T: Numeric] ...
def intersection[T: Numeric] ...
}
答案 1 :(得分:6)
Numeric
对象中Interval
类型类的使用具有类型参数T
,该参数必须绑定在其封闭范围内的某处。 Interval
是一个唯一的常量值,无法提供该绑定。
针对此特定问题的一个解决方案是将union
和intersect
操作的定义作为普通实例方法移至Interval
类中,在哪种情况下,他们会将T
和关联的Numeric
实例与该类的其余部分进行绑定,
case class Interval[T : Numeric](from: T, to: T) {
import Numeric.Implicits._
import Ordering.Implicits._
def mid: Double = (from.toDouble + to.toDouble) / 2.0
def union(interval2: Interval[T]) =
Interval(this.from min interval2.from, this.to max interval2.to)
def intersect(interval2: Interval[T]) =
Interval(this.from max interval2.from, this.to min interval2.to)
}
但是,如果您希望将这些操作的定义与Interval
类分开,那么减少需要通过API追踪的隐式样板量的一种方法是定义自己的更高级别 - 根据Numeric [T]的级别类型类。例如,
// Type class supplying union and intersection operations for values
// of type Interval[T]
class IntervalOps[T : Numeric] {
import Ordering.Implicits._
def union(interval1: Interval[T], interval2: Interval[T]) =
Interval[T](interval1.from min interval2.from, interval1.to max interval2.to)
def intersect(interval1: Interval[T], interval2: Interval[T]) =
Interval[T](interval1.from max interval2.from, interval1.to min interval2.to)
}
implicit def mkIntervalOps[T : Numeric] = new IntervalOps[T]
在使用中看起来像,
def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : IntervalOps[T]) = {
import ops._
val i3 = union(i1, i2)
val i4 = intersect(i1, i2)
(i3, i4)
}
第三个选项将这两个选项结合起来,使用隐式定义来使用其他方法来丰富原始类
class IntervalOps[T : Numeric](interval1 : Interval[T]) {
import Ordering.Implicits._
def union(interval2: Interval[T]) =
Interval[T](interval1.from min interval2.from, interval1.to max interval2.to)
def intersect(interval2: Interval[T]) =
Interval[T](interval1.from max interval2.from, interval1.to min interval2.to)
}
implicit def enrichInterval[T : Numeric](interval1 : Interval[T]) =
new IntervalOps[T](interval1)
type Ops[T] = Interval[T] => IntervalOps[T]
然后在使用中,
def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : Ops[T]) = {
val i3 = i1 union i2
val i4 = i1 intersect i2
(i3, i4)
}