隐式对象的组合爆炸

Combinatorial explosion of implicit objects

我有一个案例class,像这样:

case class Container[T, M](value: T, modifier: M)

我想让那些 T 也有 Ordering 的人在 Container 上有一个 Ordering。我不想制作 T <: Ordered[T],因为 Container 也应该能够包含不可订购的值。

我的第一个尝试是实现 Ordered,像这样:

case class Container[T, M](value: T, modifier: M) extends Ordered[Container[T, M]] {
  override def compare(that: Container[T, M])(implicit ev: Ordering[T]): Int = ev.compare(value, that.value)
}

但这显然不起作用:由于 implicit 参数,compare 不再实现该特征。

于是我决定尝试一种 class 方法:

class ContainerOrdering[T, M](implicit ev: Ordering[T]) extends Ordering[Container[T, M]] {
  override def compare(x: Container[T, M], y: Container[T, M]): Int = ev.compare(x.value, y.value)
}
implicit object ContainerOrderingInt extends ContainerOrdering[Int, Int]

这可行(如果我也 import Ordering.Implicits._),但现在我遇到了一个新问题:对于每个类型 M,我需要一个单独的隐式对象。现在我想在 M 位置使用的类型不多了(事实上,它们都派生自我在其他地方定义的密封特征),但这仍然意味着我隐式对象的组合爆炸需要定义。我同意每个 T 都有一个单独的隐式对象,但 M 确实应该与此正交。

一定有更好的方法来做到这一点。也许我可以利用 M 扩展密封特征这一事实。但是,我一直无法这样做。有什么建议吗?

Ordering 放入伴生对象中!

object Container {
    implicit def ordering[T: Ordering, M] = new Ordering[Container[T, M]] {
        override def compare(x: Container[T, M], y: Container[T, M]): Int =
            implicitly[Ordering[T]].compare(x.value, y.value)
    }
}

现在您可以在需要的地方使用 import Container._ 进行排序。

(PS:真正的诀窍当然是使排序隐式化,使您不必为每种可能的类型定义每一个单独的排序。)