隐式对象的组合爆炸



我有一个case类,像这样:

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

我想让那些有OrderingTContainer上有一个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 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:真正的技巧当然是使排序隐式,从而使您不必为每种可能的类型定义每一个排序)

最新更新