通常最好使用Ordering
而不是Ordered
. Ordering
是一个类型类并且比Ordered
(如果只是因为Ordered
必须由类型实现来比较,而Ordering
你可以在外面定义这个)灵活得多。要为您的类型定义自然排序(默认Ordering
实例),您只需在伴随对象中定义一个隐式排序值。
所以,序言就足够了。好的是当使用Ordering
你想做的事情时非常简单,因为元组有一个隐式排序(假设元组元素本身有一个排序)`:
object Foo {
implicit val FooOrdering = Ordering.by{ foo: Foo =>
(foo.length, foo.x, foo.y, foo.z)
}
}
此外,还有一个隐式转换,它将任何具有Ordering
类型类实例的值转换为一个Ordered
值(请参阅Ordered.orderingToOrdered
),因此我们没有什么特别的事情可以自动将 的任何实例传递Foo
给期望一个 的函数Ordered[Foo]
)
更新:关于你的新问题:
稍微相关 - 有没有办法组成订单?
一种方法是使用基于Ordering.by
元组并转换为元组的大部分相同技术,但显式传递排序以组合:
val byXOrdering = Ordering.by{ foo: Foo => foo.x }
val byYOrdering = Ordering.by{ foo: Foo => foo.y }
val byZOrdering = Ordering.by{ foo: Foo => foo.z }
// Compose byXOrdering and byYOrdering:
val byXThenYOrdering = Ordering.by{ foo: Foo => (foo, foo) }(Ordering.Tuple2(byXOrdering, byYOrdering))
// Compose byXOrdering and byYOrdering and byZOrdering:
val byXThenYThenZOrdering = Ordering.by{ foo: Foo => (foo, foo, foo) }(Ordering.Tuple3(byXOrdering, byYOrdering, byZOrdering))
但它相对“嘈杂”。仅使用标准库我找不到更好的东西,所以我实际上建议使用我们自己的助手:
final class CompositeOrdering[T]( val ord1: Ordering[T], val ord2: Ordering[T] ) extends Ordering[T] {
def compare( x: T, y: T ) = {
val comp = ord1.compare( x, y )
if ( comp != 0 ) comp else ord2.compare( x, y )
}
}
object CompositeOrdering {
def apply[T]( orderings: Ordering[T] * ) = orderings reduceLeft (_ orElse _)
}
implicit class OrderingOps[T]( val ord: Ordering[T] ) extends AnyVal {
def orElse( ord2: Ordering[T] ) = new CompositeOrdering[T]( ord, ord2 )
}
可以这样使用:
val byXOrdering = Ordering.by{ foo: Foo => foo.x }
val byYOrdering = Ordering.by{ foo: Foo => foo.y }
val byZOrdering = Ordering.by{ foo: Foo => foo.z }
// Compose byXOrdering and byYOrdering:
val byXThenYOrdering = byXOrdering orElse byYOrdering
// Compose byXOrdering and byYOrdering and byZOrdering:
val byXThenYThenZOrdering = byXOrdering orElse byYOrdering orElse byZOrdering
或者更简单,像这样:
// Compose byXOrdering and byYOrdering:
val byXThenYOrdering = CompositeOrdering(byXOrdering, byYOrdering)
// Compose byXOrdering and byYOrdering and byZOrdering:
val byXThenYThenZOrdering = CompositeOrdering(byXOrdering, byYOrdering, byZOrdering)
CompositeOrdering.apply
基本上就是你Ordering.multipleBy
在问题中所说的。