如何将Ordering显式传递给隐式扩充

时间:2019-02-12 10:36:47

标签: scala

我已经定义了以下Seq的隐式充实

class OrderedSeqEnricher[T <% Ordered[T]](seq: Seq[T]) {

    def binarySearch(e: T): Int = binarySearch(e, 0, seq.length)

    private def binarySearch(e: T, start: Int, end: Int): Int =
        if (start < end) {
            val mid = start + (end - start) / 2
            if (e < seq(mid)) binarySearch(e, start, mid)
            else if (e > seq(mid)) binarySearch(e, mid + 1, end)
            else mid
        }
        else -start
}

implicit def toOrderedSeqEnricher[T <% Ordered[T]](seq: Seq[T]) = new OrderedSeqEnricher(seq)

我遇到的问题是,在某些情况下,我想使用seq来存储ID,这些ID用于查找树中的对象,然后比较这些对象。像这样:

implicit def ordering: Ordering[Int] = (i1: Int, i2: Int) =>
    if (tree(i1).myCompare(tree(i2)) < 0) -1 else 1

有没有一种方法可以明确指定这是要使用的顺序,而不是将它们视为简单的整数?

1 个答案:

答案 0 :(得分:2)

  1. 您可以将一个类和一个implicit def组合在一起,而该类只需使用implicit class进行构造即可:

    implicit class OrderedSeqEnricher[T <% Ordered[T]](seq: Seq[T]) { ... }
    
  2. 引用Ordered文档:

      

    具有单一自然顺序的数据的特征。有关是否使用scala.math.Ordering的更多信息,请参阅使用此特征之前的scala.math.Ordering。

    因此您不能将Ordering<% Ordered[T]一起使用。相反,更喜欢: Ordering(除非您有一些非常具体的理由使用Ordered,否则我通常会这样做):

    implicit class OrderedSeqEnricher[T : Ordering](seq: Seq[T]) { ... }
    

然后,您可以将

明确传递给ordering
 new OrderedSeqEnricher(someIntSeq)(ordering).binarySearch(...)

或者将参数而不是类放在方法上:

implicit class OrderedSeqEnricher[T](seq: Seq[T]) {

    def binarySearch(e: T)(implicit ordering: Ordering[T]): Int = binarySearch(e, 0, seq.length)

    private def binarySearch(e: T, start: Int, end: Int)(implicit ordering: Ordering[T]): Int =
        if (start < end) {
            val mid = start + (end - start) / 2
            if (e < seq(mid)) binarySearch(e, start, mid)
            else if (e > seq(mid)) binarySearch(e, mid + 1, end)
            else mid
        }
        else -start
}

someIntSeq.binarySearch(...)(ordering)

另一个可能的好主意是使id与Int s成为一个单独的值类(以防止对id无意义的任何运算,例如算术运算):

class Id(value: Int) extends AnyVal { ... }

object Id {
  implicit def ordering(implicit tree: Tree): Ordering[Id] = (i1: Id, i2: Id) =>
    // assumes trees are changed to apply(Id) instead of apply(Int)
    if (tree(i1).myCompare(tree(i2)) < 0) -1 else 1
}