Scala использует черту Ordering[T]
для методов sorted
, min
и max
коллекции типа T
. Он может автоматически генерировать экземпляры Ordering[T]
для T
, которые расширяют Ordered[T]
.
Из-за совместимости с Java Ordering[T]
расширяет java.util.Comparator[T]
, который инвариантен в T
, поэтому Ordering[T]
также должен быть инвариантен в T
. Смотрите эту проблему: SI-7179 .
Это означает, что Scala не может генерировать экземпляры Ordering[T]
для T
, которые являются подклассами классов, которые реализуют Ordered
.
В вашем коде у вас есть val collection = List(biggerValue, lesserValue)
, который имеет тип List[Value[Int]]
. Value
не имеет своих Ordered
или Ordering
, поэтому Scala не может отсортировать это collection
.
Чтобы исправить, вы можете указать collection
, чтобы иметь тип List[ValueTrait[Int]]
:
val collection = List[ValueTrait[Int]](biggerValue, lesserValue)
Или определить явное Ordering
для Value[T]
:
object Value {
implicit def ord[T]: Ordering[Value[T]] =
Ordering.by(t => t: ValueTrait[T])
}
Вы можете также рассмотреть возможность использования другой конструкции в этой задаче, если она соответствует вашим другим требованиям:
В вашем коде все экземпляры ValueTrait[TYPE]
имеют значение типа Double
, а различия в подклассе и TYPE
не кажутся важными во время выполнения. Таким образом, вы можете просто определить case class Value(value: Double)
и иметь разные фабричные методы для создания Value
из различных типов аргументов.
case class Value(value: Double) extends Ordered[Value] {
override def compare(that: Value): Int = this.value compareTo that.value
}
object Value {
def fromList[A](list: List[A], function: (A, A) => Double): Value =
Value((list, list.tail).zipped.map(function).sum)
}
И использование:
scala> val lesserValue = Value.fromList(List(1, 2), evaluationFunction)
lesserValue: Value = Value(1.0)
scala> val biggerValue = Value.fromList(List(2, 1), evaluationFunction)
biggerValue: Value = Value(10.0)
scala> val collection = List(biggerValue, lesserValue)
collection: List[Value] = List(Value(10.0), Value(1.0))
scala> (collection.min, collection.max, collection.sorted)
res1: (Value, Value, List[Value]) = (Value(1.0),Value(10.0),List(Value(1.0), Value(10.0)))