我有一个case类,像这样:
case class Container[T, M](value: T, modifier: M)
我想让那些有Ordering
的T
在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 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:真正的技巧当然是使排序隐式,从而使您不必为每种可能的类型定义每一个排序)