我有一个实现了Scala的有序特征的特征:
package stackQuestions
trait ValueTrait[TYPE] extends Ordered[ValueTrait[TYPE]]{
def value: Double
}
和一个子类:
package stackQuestions
class Value[A](list: List[A], function: (A, A) => Double) extends ValueTrait[A] {
private val _value: Double = list.zip(list.tail).map(pair => function(pair._1, pair._2)).sum
override def value: Double = _value
override def compare(that: ValueTrait[A]): Int = {
(this.value - that.value).signum
}
}
基本上,使用提供的函数创建Value对象时,将计算该值。我要实现的是基于Value对象的值对它们进行排序。这应该通过有序特征来保证。我为此编写了一些简单的测试:
package stackQuestions
import org.scalatest.FunSpec
class ValueTest extends FunSpec {
def evaluationFunction(arg1: Int, arg2: Int): Double = {
if (arg1 == 1 && arg2 == 2) return 1.0
if (arg1 == 2 && arg2 == 1) return 10.0
0.0
}
val lesserValue = new Value(List(1, 2), evaluationFunction) // value will be: 1.0
val biggerValue = new Value(List(2, 1), evaluationFunction) // value will be: 10.0
describe("When to Value objects are compared") {
it("should compare by calculated value") {
assert(lesserValue < biggerValue)
}
}
describe("When to Value objects are stored in collection") {
it("should be able to get max value, min value, and get sorted") {
val collection = List(biggerValue, lesserValue)
assertResult(expected = lesserValue)(actual = collection.min)
assertResult(expected = biggerValue)(actual = collection.max)
assertResult(expected = List(lesserValue, biggerValue))(actual = collection.sorted)
}
}
}
但是,当sbt test -Xlog-implicits
出现错误消息时:
[info] Compiling 1 Scala source to /project/target/scala-2.11/test-classes ...
[error] /project/src/test/scala/stackQuestions/ValueTest.scala:24:64: diverging implicit expansion for type Ordering[stackQuestions.Value[Int]]
[error] starting with method $conforms in object Predef
[error] assertResult(expected = lesserValue)(actual = collection.min)
[error] ^
[error] /project/src/test/scala/stackQuestions/ValueTest.scala:25:64: diverging implicit expansion for type Ordering[stackQuestions.Value[Int]]
[error] starting with method $conforms in object Predef
[error] assertResult(expected = biggerValue)(actual = collection.max)
[error] ^
[error] /project/src/test/scala/stackQuestions/ValueTest.scala:27:83: diverging implicit expansion for type scala.math.Ordering[stackQuestions.Value[Int]]
[error] starting with method $conforms in object Predef
[error] assertResult(expected = List(lesserValue, biggerValue))(actual = collection.sorted)
[error] ^
[error] three errors found
[error] (Test / compileIncremental) Compilation failed
[error] Total time: 1 s, completed 2018-09-01 08:36:18
我已经阅读了类似的问题并阅读了以下内容:
我知道编译器对如何选择适当的函数进行比较感到困惑。我知道我可以使用sortBy(obj => obj.fitness)
来解决这个问题,但是有什么方法可以使用更简洁的sorted
方法呢?
答案 0 :(得分:2)
Scala对类型为Ordering[T]
的集合的方法sorted
,min
和max
使用T
特征。它可以为扩展了Ordering[T]
的{{1}}的{{1}}实例自动生成。
由于Java兼容性T
扩展了Ordered[T]
中不变的Ordering[T]
,因此java.util.Comparator[T]
也必须在T
中不变。请参见此问题:SI-7179。
这意味着Scala无法为实现Ordering[T]
的类的子类T
生成Ordering[T]
的实例。
在您的代码中,您有T
,其类型为Ordered
。 val collection = List(biggerValue, lesserValue)
没有自己的List[Value[Int]]
或Value
,因此Scala无法对此Ordered
进行排序。
要解决此问题,您可以指定Ordering
的类型为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