独立于外部 class 实例为内部 class 定义一个 Ordered 实例

Defining an Ordered instance for an Inner class independently from Outer class instance

我正在尝试指定对所有 AbstractTaskKey 进行排序,而不管它们属于哪个 AbstractTaskKeys 容器。

如下面的代码所示,很容易为每个特定的外部 class 指定一个顺序,但这意味着在每个不同的地方我想对 allKeys 进行排序我需要使用 sortBy(或定义一个专门用于范围内的任何子外部 class 的隐式 ord。

我希望能够为 AbstractTaskKey 定义一个适用于 AbstractTaskKeys 的所有子 class 的 Ordered 实例。

我尝试按照其他 SO 帖子的建议在一堆不同的地方添加各种方差注释、subclasses 和通配符,但无济于事。

如何使我的 AbstractTaskKey 的 Ordered 实例(或 Ordering)通用?

object HelloWorld {
  def main(args: Array[String]) {
    val someTaskKeyConsumer = new SomeTaskKeyConsumer[FooTaskKeys](FooTaskKeys)
    println(someTaskKeyConsumer.sortedKeysLength)
  }
}

trait AbstractTaskKeys {
  // Tried: traitAbstractTaskKey extends Ordered[...] too
  trait AbstractTaskKey {val id: Int}

  // Really I want _#AbstractTaskKey or (_ <: AbstractTaskKeys)#AbstractTaskKey
  implicit val ord: Ordering[AbstractTaskKey] = Ordering.by(_.id)
  val allKeys: List[AbstractTaskKey]
}

class SomeTaskKeyConsumer[TaskKeys <: AbstractTaskKeys](taskKeys: TaskKeys) {
  def sortedKeysLength: Int
    // No implicit Ordering defined for SomeTaskKeyConsumer.this.taskKeys.AbstractTaskKey
    //= taskKeys.allKeys.sorted.length     
    = taskKeys.allKeys.sortBy(_.id).length // works fine
}

trait FooTaskKeys extends AbstractTaskKeys
object FooTaskKeys extends FooTaskKeys {
  case object FooTask0 extends AbstractTaskKey {val id = 0}
  val allKeys = List(FooTask0)

关键是将隐式 Ordering 放在 AbstractTaskKey 的伴随对象中,这样它就在编译器需要填充隐式时搜索的范围内。

trait AbstractTaskKeys {
  trait AbstractTaskKey {val id: Int}
  object AbstractTaskKey {
    implicit val ord: Ordering[AbstractTaskKey] = Ordering.by(_.id)
  }
  val allKeys: List[AbstractTaskKey]
}

class SomeTaskKeyConsumer[TaskKeys <: AbstractTaskKeys](taskKeys: TaskKeys) {
  def sortedKeysLength: Int = taskKeys.allKeys.sorted.length
}

这不允许您比较 AbstractTaskKeys 的不同封闭实例中的 AbstractTaskKey 实例,但这似乎不是您要查找的内容。如果是,您可以定义一个 Ordering ,其路径相关类型为 AbstractTaskKeys#AbstractTaskKey:

implicit val ord: Ordering[AbstractTaskKeys#AbstractTaskKey] = Ordering.by(_.id)