(我每天晚上都在使用Scala,并且在2.8.0b1 RC4中看到相同的行为。我是Scala的新人。)

我有两个SortedMap,我想组成它们的联合。这是我要使用的代码:

import scala.collection._

object ViewBoundExample {
    class X
    def combine[Y](a: SortedMap[X, Y], b: SortedMap[X, Y]): SortedMap[X, Y] = {
        a ++ b
    }
    implicit def orderedX(x: X): Ordered[X] = new Ordered[X] { def compare(that: X) = 0 }
}

这里的想法是'implicit'语句,意味着X可以转换为Ordered[X],然后将SortedMap组合成另一个SortedMap而不是仅映射即可。

当我编译时,我得到
sieversii:scala-2.8.0.Beta1-RC4 scott$ bin/scalac -versionScala compiler version
2.8.0.Beta1-RC4 -- Copyright 2002-2010, LAMP/EPFL

sieversii:scala-2.8.0.Beta1-RC4 scott$ bin/scalac ViewBoundExample.scala
ViewBoundExample.scala:8: error: type arguments [ViewBoundExample.X] do not
    conform to method ordered's type parameter bounds [A <: scala.math.Ordered[A]]
        a ++ b
          ^
one error found

如果该类型参数绑定(bind)为[A <% scala.math.Ordered[A]]而不是[A <: scala.math.Ordered[A]],似乎我的问题就解决了。不幸的是,我什至无法弄清楚“ordered”方法的用途!谁能帮我追踪一下?

失败了,我打算怎么做才能产生两个SortedMap的并集?如果我删除了Combine的返回类型(或将其更改为Map),那么一切正常---但是我不能依靠排序后的返回值!

最佳答案

当前,您正在使用的是scala.collection.SortedMap特性,其++方法是从MapLike特性继承的。因此,您看到以下行为:

scala> import scala.collection.SortedMap
import scala.collection.SortedMap

scala> val a = SortedMap(1->2, 3->4)
a: scala.collection.SortedMap[Int,Int] = Map(1 -> 2, 3 -> 4)

scala> val b = SortedMap(2->3, 4->5)
b: scala.collection.SortedMap[Int,Int] = Map(2 -> 3, 4 -> 5)

scala> a ++ b
res0: scala.collection.Map[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5)

scala> b ++ a
res1: scala.collection.Map[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5)
++返回结果的类型是Map[Int, Int],因为这是唯一有意义的++对象的MapLike方法返回的类型。看来++保留了SortedMap的sorted属性,我猜这是因为++使用抽象方法来进行串联,并且这些抽象方法被定义为保持 map 的顺序。

要合并两个排序的映射,建议您使用scala.collection.immutable.SortedMap
scala> import scala.collection.immutable.SortedMap
import scala.collection.immutable.SortedMap

scala> val a = SortedMap(1->2, 3->4)
a: scala.collection.immutable.SortedMap[Int,Int] = Map(1 -> 2, 3 -> 4)

scala> val b = SortedMap(2->3, 4->5)
b: scala.collection.immutable.SortedMap[Int,Int] = Map(2 -> 3, 4 -> 5)

scala> a ++ b
res2: scala.collection.immutable.SortedMap[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5)

scala> b ++ a
res3: scala.collection.immutable.SortedMap[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5)

SortedMap特征的实现声明了一个++方法,该方法返回SortedMap

现在,对有关类型边界的问题有几个答案:
  • Ordered[T]是一个特征,如果将其混合在一个类中,则指定可以使用<>=>=<=比较该类。您只需要定义抽象方法compare(that: T),该方法将-1返回this < that,将1返回this > that,将0返回this == that。然后根据compare的结果在特征中实现所有其他方法。
  • T <% U表示绑定(bind)在Scala中的 View 。这意味着T类型可以是U的子类型,也可以通过范围内的隐式转换将其隐式转换为U。如果您放置<%而不是<:,则该代码有效,因为X不是Ordered[X]的子类型,但可以使用Ordered[X]隐式转换将其隐式转换为OrderedX

  • 编辑:关于您的评论。如果您使用的是scala.collection.immutable.SortedMap,那么您仍在编程而不是实现的接口(interface),因为不可变的SortedMap被定义为trait。您可以将其视为scala.collection.SortedMap的更特殊的特征,它提供了其他操作(例如++返回SortedMap)和不可变的属性。这符合Scala的理念-倾向于不可变-因此我认为使用不可变SortedMap没有任何问题。在这种情况下,您可以保证结果一定会被排序,并且由于集合是不可变的,因此无法更改。

    虽然,我仍然感到奇怪的是,scala.collection.SortedMap没有提供++方法,女巫返回了SortedMap作为结果。我所做的所有有限测试似乎都表明,将两个scala.collection.SortedMap串联在一起的结果确实会生成一个保留了sorted属性的映射。

    10-06 11:13