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

Goo*_*han 3 for-loop scala

    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)
    }
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果我定义了这样的方法:

def genSet:Set[Int] = {
  TreeSet(5, 4, 3, 2, 1)
}
Run Code Online (Sandbox Code Playgroud)

当我想使用for循环时

for (i <- genSet; x = i + 1) {
  println(x)
}
Run Code Online (Sandbox Code Playgroud)

结果是未排序的,如何在不更改genSet返回类型的情况下修复此行为.如果我像下面一样使用循环,它会很好,但我希望保持上面的代码风格.

for (i <- genSet) {
  val x = i + 1
  println(x)
}
Run Code Online (Sandbox Code Playgroud)

Ken*_*oom 12

为什么map版本结束了未分类

除了返回选择适当返回类型的类型之外,该map方法(使用我们将调用的函数调用func)采用一个隐式CanBuildFrom参数,该参数考虑了map被调用的集合的func类型.这用于制作Map.map[Int]或BitSet.map[String]做正确的事情(返回通用列表)同时Map.map[(String,Int)]或者BitSet.map[Int]也做正确的事情(分别返回a Map和a BitSet).

该CanBuildFrom是在编译时选择,所以它必须根据选择静态类型的调用集合map上(在编译时,编译器知道的类型).静态类型set是TreeSet,但静态类型diffset是Set.两者的动态类型(在运行时)是TreeSet.

当你打电话map给set(a TreeSet)时,编译器选择immutable.this.SortedSet.canBuildFrom[Int](math.this.Ordering.Int)为CanBuildFrom.

当你打电话map给diffset(a Set)时,编译器选择immutable.this.Set.canBuildFrom[Int]为CanBuildFrom.

为什么for版本结束了未分类

循环

for (i <- genSet; x = i + 1) {
  println(x)
}
Run Code Online (Sandbox Code Playgroud)

desugars into

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)
            }))
Run Code Online (Sandbox Code Playgroud)

desugared版本包括一个map功能,将使用未分类CanBuildFrom,如上所述.

另一方面,循环

for (i <- genSet) {
  val x = i + 1
  println(x)
}
Run Code Online (Sandbox Code Playgroud)

desugars into

genSet.foreach(((i) => {
              val x = i.$plus(1);
              println(x)
            }))
Run Code Online (Sandbox Code Playgroud)

CanBuildFrom因为没有返回新的集合,所以根本不使用a .

  • @sblundy:根据他试图对`SortedSet`中的元素顺序做什么,他实际上想在调用map之前调用`toSeq`(如果该点以与其顺序相对应的顺序遍历映射值) set),或者他可能想调用`toSortedSet`(如果该点是映射值的范围查找).适当的行为完全与他计划如何使用有序性有关. (2认同)

Dan*_*ral 6

Set不保证订购.即使基础类是a TreeSet,如果预期的结果是a,Set你将在第一次转换中放松顺序.

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