Scala隐含伴随对象中的Numeric [T]

Per*_*ing 6 scala numeric implicit implicit-conversion implicits

我有以下通用的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
}
Run Code Online (Sandbox Code Playgroud)

典型用例:Interval [Double]或Interval [Int].为了添加二元联合交集运算符,我(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)
  }

}  
Run Code Online (Sandbox Code Playgroud)

在两种方法中复制(implicit num: Numeric[T])import num.mkOrderingOps内部都是丑陋的样板.在Interval对象本身的层次上,有一些方法可以做到这一次吗?

Did*_*ont 8

就在这里.

首先进口.您可以在Interval的范围内导入Ordering.Implicits._.

object Interval {
   import Ordering.Implicits._

   def union[T](....)(implicit num: Numeric[T]) = {
     // do not import num.mkOrderingOps
     ...
   }
   ...
}
Run Code Online (Sandbox Code Playgroud)

有了这些含义,当它找到一个排序操作时,它会在操作发生的范围内寻找隐式的Ordering(Numeric is a Ordering).在每个例程中,恰好有一个隐含的范围.如果您也需要算术运算,也可以导入Numeric.Implicits._

现在有了隐含的论点.语言中有一个快捷方式,称为上下文绑定:您可以编写def f[T: X](args)而不是def f[T](args)(implicit someName: X[T])

不同之处在于你没有带上下文绑定的隐式名称(你可以使用implictly [T]但是这几乎不会更短.幸运的是,你不再需要一个名字了,导入Ordering.Implicits._

所以

object Interval {
   import Ordering.Implicits._
   // also import Numeric.Implicits._ if you need +,-,*,/ ...
   def union[T: Numeric] ...
   def intersection[T: Numeric] ...
}
Run Code Online (Sandbox Code Playgroud)


Mil*_*bin 6

对象中Numeric类型类的使用Interval具有一个类型参数T,该参数必须绑定在其封闭范围内的某处.Interval作为唯一的常量值,不能提供该绑定.

这个特定问题的一个解决方案是将您unionintersect操作的定义作为普通实例方法移动到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)
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您希望将这些操作的定义与Interval类分开,那么减少需要追踪API的隐式样板量的一种方法是根据数值来定义您自己的更高级类型类[ 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]
Run Code Online (Sandbox Code Playgroud)

在使用中看起来像,

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)
}
Run Code Online (Sandbox Code Playgroud)

第三个选项将这两个选项组合在一起,使用隐式定义来使用其他方法丰富原始类,

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]
Run Code Online (Sandbox Code Playgroud)

然后在使用中,

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)
}
Run Code Online (Sandbox Code Playgroud)