声明类型不同时的不同行为(Set vs TreeSet)

时间:2010-12-30 14:42:05

标签: scala for-loop

    var set = TreeSet(5,4,3,2,1)
    println(set)

    val diffSet: TreeSet[Int] = set
    // if I change above code to val diffSet: Set[Int] = set
    // the result is unsorted set.

    for (i <- diffSet; x = i) {
        println(i)
    }
    println("-" * 20)
    // the above code translates to below and print the same result
    val temp = diffSet.map(i => (i, i))
    for ((i, x) <- temp) {
        println(i)
    }

我的问题是我是否定义了这样的方法:

def genSet:Set[Int] = {
  TreeSet(5, 4, 3, 2, 1)
}

当我想使用for循环时

for (i <- genSet; x = i + 1) {
  println(x)
}

结果未排序,如何修改此行为而不更改genSet的返回类型。如果我像下面一样使用循环,它会没问题,但我希望保持上面的代码风格。

for (i <- genSet) {
  val x = i + 1
  println(x)
}

4 个答案:

答案 0 :(得分:12)

为什么map版本结束了未排序的

map方法(使用我们称之为func的函数调用)采用隐式CanBuildFrom参数,该参数考虑了map的集合类型正在调用,除了func返回以选择适当的返回类型的类型。这用于使Map.map[Int]BitSet.map[String]做正确的事情(返回通用列表),而Map.map[(String,Int)]BitSet.map[Int]也做正确的事情(返回{{1}分别是Map

在编译时选择BitSet,因此必须根据您调用CanBuildFrom的集合的 static 类型来选择它(编译器知道的类型)约在编译时)。 map的静态类型为set,但TreeSet的静态类型为diffset。两者的动态类型(在运行时)是Set

当您在TreeSetmap)上致电set时,编制者会选择TreeSet作为immutable.this.SortedSet.canBuildFrom[Int](math.this.Ordering.Int)

当您在CanBuildFrommap)上致电diffset时,编制者会选择Set作为immutable.this.Set.canBuildFrom[Int]

为什么CanBuildFrom版本结束了未排序的

循环

for

desugars into

for (i <- genSet; x = i + 1) {
  println(x)
}

desugared版本包含一个genSet.map(((i) => { val x = i.$plus(1); scala.Tuple2(i, x) })).foreach(((x$1) => x$1: @scala.unchecked match { case scala.Tuple2((i @ _), (x @ _)) => println(x) })) 函数,它将使用我上面解释的未排序的map

另一方面,循环

CanBuildFrom

desugars into

for (i <- genSet) {
  val x = i + 1
  println(x)
}

根本不使用genSet.foreach(((i) => { val x = i.$plus(1); println(x) })) ,因为没有返回新的集合。

答案 1 :(得分:6)

Set不保证订购。即使基础类是TreeSet,如果预期结果是Set,您将在第一次转换中失去排序。

如果您想要订购,请不要使用Set。我建议说,SortedSet

答案 2 :(得分:2)

更改genSet的签名以返回SortedSet

def genSet:SortedSet[Int] = {
  TreeSet(5, 4, 3, 2, 1)
}

这可能是某种错误。我本来希望你的代码能够运行。

我认为map是罪魁祸首。这会导致相同的行为:

for (i <- genSet.map(_ + 1)) { println(i) }

for(i <- genSet; x = i + 1)等同于for(x <- genSet.map({i => i + 1}))

答案 3 :(得分:0)

你可以这样做:

scala> for (i <-genSet.view; x = i + 1) println(x)
2
3
4
5
6

虽然,这是一种技巧,当你在几个月后看它时,你可能想知道为什么你添加了.view ......