创建名为test.WsTemp
的ScalaIDE工作表后,我编写了下面的代码,并在特征Enum
中收到了一行错误:
scala.math.Ordering[U]
LowPriorityOrderingImplicits
进行隐式扩展
Ordering
U
(implicit ord: scala.math.Ordering[U])List[U]
,未指定的值参数ord
。为什么这不起作用,因为它显而易见Val
扩展Ordered[Val]
?
object WsTemp {
trait Val extends Ordered[Val] {
val id: Int
val name: String
final def compare(that: Val) = this.id - that.id
override def toString: String = name
}
trait Enum[U <: Val] {
protected def init: Set[U]
val all = init
val allOrdered = all.toList.sorted // <-- Receiving error here
val byId = all.map(x => (x.id, x)).toMap
val byName = all.map(x => (x.name, x)).toMap
def apply(id: Int) = byId.get(id)
def apply(name: String) = byName.get(name)
}
sealed class Value(val id: Int, val name: String) extends Val
object Suit extends Enum[Value] {
override def init: Set[Value] = //Set()
Set(
new Value(0, "Spade")
, new Value(1, "Club")
, new Value(2, "Diamond")
, new Value(3, "Heart")
)
val Spade = Suit.byId(0)
val Club = Suit.byId(1)
val Diamond = Suit.byId(2)
val Heart = Suit.byId(3)
}
val all = Suit.all
val allOrdered = Suit.allOrdered
val byId = Suit.byId
val byName = Suit.byName
val spade = Suit.Spade
}
答案 0 :(得分:4)
Ordering
和Ordered
都是不变的,因此U
是Val
的子类型(由关系U <: Val
表示)并不意味着Ordering[Val]
可以用作Ordering[U]
。
因此,即使Val
扩展Ordered[Val]
这一事实意味着您隐式获得Ordering[Val]
,这对Ordering[U]
也没有任何意义。
因此,编译器抱怨它无法找到Ordering[U]
类型的隐式值(调用sorted
所需的)。
使用小代码段很容易说明prolbem,该代码段模仿Ordered
和Ordering
的情况:
object WsTemp {
trait MyOrdered[T]
trait MyOrdering[T]
object MyOrdering {
implicit def toOrdering[A <% MyOrdered[A]]: MyOrdering[A] = new MyOrdering[A]{}
}
trait Val extends MyOrdered[Val]
def test[T](implicit ord: MyOrdering[T]) {}
trait Enum[U <: Val] {
def callTest() { test[U] }
}
}
产生以下错误:
<console>:20: error: could not find implicit value for parameter ord: WsTemp.MyOrdering[U]
def callTest() { test[U] }
但是如果你使MyOrdered
和MyOrdering
协变,那么编译很好:
trait MyOrdered[+T]
trait MyOrdering[+T]
...
显然,您无法更改scala的Ordering
或Ordered
以使其不变。
现在,解决问题的一种方法是安排代码,以便Val
不会扩展Ordered[Val]
,而是扩展Ordered[X]
,其中X
是实际类型您想拥有Ordering
(此处为X
= U
)。这可以通过 F-bounded多态来实现:
trait Val[Self<:Val[Self]] extends Ordered[Self] {
//...
}
trait Enum[U <: Val[U]] {
//...
}
sealed class Value(val id: Int, val name: String) extends Val[Value]
//...
U
现在是Val[U]
的子类型,它是Ordered[U]
的子类型(与之前的Ordered[Val]
子类型相反) ,所以你现在隐含地得到一个Ordering[U]
,它(隐式)传递给sorted
。问题解决了。
答案 1 :(得分:1)
正如RégisJean-Gilles所说,“Ordering and Ordered都是不变的,所以U是Val的子类型(由U&lt;:Val表示)并不意味着Ordering [Val]可以用作Ordering [U]。所以即使Val扩展Ordered [Val]意味着你隐式得到一个Ordering [Val],这对Ordering [U]来说没有任何意义。“
解决此问题的一种非常简单的方法是指定要用于排序方法的类型。替换:
val allOrdered = all.toList.sorted
使用:
val allOrdered = all.toList.sorted[Val]