scala文档说Enumeration.Val是有序的,但是当我尝试对要求它们支持排序的枚举值强制执行类型限制时,我会得到不一致的行为:
object Dogs extends Enumeration {
val Sam, Tom, Rover = Value
}
def doSomething[A <% Ordered[A]](a : List[A]) : Unit = {
println(a.sortWith(_ < _))
}
import Dogs._
val xs = List(Rover, Tom, Sam, Sam, Rover)
println(xs.sortWith(_ < _)) // works!
doSomething(xs) // fails =(
在最后两个语句中,第一个工作并显示Enumeration值已定义排序。第二个错误:
could not find implicit value for evidence parameter of type (this.Dogs.Value) => Ordered[this.Dogs.Value]
如何解决此问题并在需要排序的泛型方法中使用枚举值?
答案 0 :(得分:9)
问题在于Value
执行者Ordered[Enumeration#Value]
,而不是Ordered[Dogs.Value]
。我不知道这个的理由,不可能以另一种方式去做。
这对于直接比较两个值的简单情况就足够了 - 它只是一个普通的方法调用:
scala> (Rover: Ordered[Enumeration#Value]).<(Sam)
res44: Boolean = false
但是,A
中的类型参数Ordered
是不变的,因此当您要求将类型参数设置为Ordered[A]
时,仅使用Dogs.Value <: Ordered[Enumeration#Value]
是不够的。如果A
是反变量,则允许这样做,但它也会导致类型推断的其他问题。
您可以通过使用Enumeration#Value
静态输入列表来解决此问题:
scala> val xs = List[Enumeration#Value](Rover, Tom, Sam, Sam, Rover)
xs: List[Enumeration#Value] = List(Rover, Tom, Sam, Sam, Rover)
scala> doSomething(xs)
List(Sam, Sam, Tom, Rover, Rover)
或者,通过将type参数显式传递给doSomething
:
scala> doSomething[Enumeration#Value](List(Rover, Sam))
List(Sam, Rover)
或者,更好的是,放宽对类型参数的要求,在这种情况下基本上将Ordered
视为逆变。
scala> def doSomething[A <% Ordered[_ >: A]](xs : List[A]) = xs sortWith (_ < _)
doSomething: [A](xs: List[A])(implicit evidence$1: (A) => Ordered[_ >: A])List[A]
scala> doSomething(List(Rover, Sam))
res47: List[Dogs.Value] = List(Sam, Rover)
为什么这样做?
scala> Rover: Ordered[_ <: Enumeration#Value]
res52: scala.math.Ordered[_ <: Enumeration#Value] = Rover