【问题标题】:Error of "No implicit ordering defined for U" where a trait which has extended Ordered“没有为 U 定义隐式排序”的错误,其中扩展了 Ordered 的特征
【发布时间】:2013-02-10 00:53:12
【问题描述】:

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

  1. 类型 scala.math.Ordering[U] 的发散隐式扩展从在 trait LowPriorityOrderingImplicits 中排序的方法开始
  2. 没有为U 定义隐式Ordering
  3. 排序方法的参数不足:(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
}

【问题讨论】:

    标签: scala traits


    【解决方案1】:

    OrderingOrdered 都是不变的,所以UVal 的子类型(由关系U &lt;: Val 表示)并不意味着可以使用Ordering[Val]作为Ordering[U]。 因此,即使 Val 扩展 Ordered[Val] 意味着您隐含地获得了一个 Ordering[Val],但这对于 Ordering[U] 没有任何意义。

    因此编译器抱怨它找不到Ordering[U] 类型的隐式值是正确的(调用sorted 时需要该值)。

    这个问题很容易用一个模拟OrderedOrdering的小代码sn-p来说明:

    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 的 OrderingOrdered 以使其保持不变。


    现在,解决您的问题的一种方法是安排您的代码,以便 Val 不扩展 Ordered[Val],而是扩展 Ordered[X],其中 X 是您想要拥有 @987654348 的实际类型@ 代表(这里,X = U)。这可以通过F-bounded polymorphism来实现:

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

    【讨论】:

    • Jean-Gilles:Tysvm 用于回答。我已经阅读并重新阅读了您的答案,但仍然不明白。并且尝试在您的第二个代码部分中对 Self 的引用并没有发现任何问题。所以,我感觉到“Self”是一种类型,比如 U?
    • 顺便说一句,我得到了你答案的第一部分(第一部分)。只是你的第二个答案的第一行让我的 Scala 新手大脑感到困惑。
    • 这篇文章在 Twitter 上描述了你使用的“F-bounded Polymorphism”:twitter.github.com/scala_school/advanced-types.html#fbounded - 所以它是一种自引用类型,令人着迷!
    【解决方案2】:

    正如 Régis Jean-Gilles 所说,“Ordering 和 Ordered 都是不变的,因此 U 是 Val 的子类型(由关系 U <: val ordering ordered>

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

      val allOrdered = all.toList.sorted 
    

    与:

      val allOrdered = all.toList.sorted[Val] 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-24
      • 1970-01-01
      • 2012-03-16
      • 1970-01-01
      • 2017-03-10
      • 1970-01-01
      • 2020-01-27
      • 2019-02-07
      相关资源
      最近更新 更多