3

在创建一个名为 ScalaIDE 工作表后test.WsTemp,我编写了下面的代码,并且在 trait 中的一行收到三个错误Enum

  1. scala.math.Ordering[U]以 trait 中排序的方法开头的类型的发散隐式扩展LowPriorityOrderingImplicits
  2. 没有隐式Ordering定义U
  3. 排序的方法没有足够的参数:(implicit ord: scala.math.Ordering[U])List[U],未指定的值参数ord

为什么这不起作用,因为它很明显Valextends 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
}
4

2 回答 2

4

OrderingOrdered都是不变的,所以它U是 的子类型Val(由关系表示U <: Val)并不意味着Ordering[Val]可以用作Ordering[U]. 因此,即使ValextendsOrdered[Val]意味着您隐含地获得了一个Ordering[Val],但这并不意味着什么Ordering[U]

所以编译器抱怨它找不到类型的隐式值Ordering[U](这是调用所需的sorted)是正确的。

Ordered这个问题很容易用一个模仿and发生的小代码片段来说明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] }

但是如果你做MyOrderedMyOrdering协变,这编译得很好:

trait MyOrdered[+T]      
trait MyOrdering[+T]
...

显然,你不能改变 scala 的Ordering,也不Ordered能让它们保持不变。


现在,解决您的问题的一种方法是安排您的代码,以便Val不扩展Ordered[Val],而是扩展Ordered[X]X想要拥有的实际类型的位置Ordering(此处为X= U)。这可以通过F 有界多态性来实现:

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. 问题解决了。

于 2013-02-24T23:42:49.120 回答
1

正如 Régis Jean-Gilles 所说,“Ordering 和 Ordered 都是不变的,因此 U 是 Val 的子类型(由关系 U <: Val 表示)这一事实并不意味着 Ordering[Val] 可以用作一个 Ordering[U]。所以即使 Val 扩展 Ordered[Val] 意味着你隐含地得到一个 Ordering[Val],这对 Ordering[U] 没有任何意义。”

解决此问题的一种非常简单的方法是指定用于排序方法的类型。代替:

  val allOrdered = all.toList.sorted 

和:

  val allOrdered = all.toList.sorted[Val] 
于 2013-12-16T13:40:35.997 回答