Scala Traversable,Iterable,Sequence,Stream和View的语义?

时间:2011-12-20 00:44:10

标签: scala scala-collections

还有其他问题,例如Scala: What is the difference between Traversable and Iterable traits in Scala collections?How would I get the sum of squares of two Lists in Scala?可以部分回答问题。我觉得在一个地方覆盖所有这些问题是有道理的。

2 个答案:

答案 0 :(得分:33)

可遍历是集合层次结构的顶部。它的主要方法是'foreach',因此它允许为集合的每个元素做一些事情。

Iterable 可以根据可以实现的foreach创建Iterator。这定义了元素的某些顺序,尽管每个迭代器的顺序可能会改变。

Seq (uence)是一个Iterable,其中元素的顺序是固定的。因此,讨论元素的索引是有意义的。

Streams 是延迟序列。即在访问流之前,可能无法计算流的元素。这使得可以使用无限序列,如所有整数的序列。

视图是非严格版本的集合。像过滤器和视图上的映射方法只在访问相应元素时执行传递的函数。因此,巨大集合上的映射会立即返回,因为它只是在原始集合周围创建一个包装器。只有当一个人访问一个元素时,才会实际执行映射(对于该元素)。请注意,View不是一个类,但是有很多XxxView类用于各种集合。

答案 1 :(得分:2)

我想添加关于流与迭代器的一条评论。流和迭代器都可用于实现长的,非严格的,可能无限的集合,这些集合在需要之前不会计算值。

然而,在执行此操作时出现了“过早执行”的棘手问题,可以使用迭代器而不是流来避免这种问题,并且在此过程中指出了两者之间的重要语义差异。这可能最清楚地说明如下:

def runiter(start: Int) {
  // Create a stream that returns successive integers on demand, e.g. 3, 4, 5, ....
  val iter = {
    def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1)
    loop(start)
  }
  // Now, sometime later, we retrieve the values ....
  println("about to loop")
  for (x <- iter) {
    if (x < 10) println("saw value", x) else return
  }
}

此代码创建一个以给定值开始并返回连续整数的无限流。它可用作更复杂代码的替代,例如,可以打开Internet连接并根据需要从连接返回值。

结果:

scala> runiter(3)
(I computed a value,3)
about to loop
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)

请注意在实际使用流的值之前,如何计算第一个值所需的执行。如果这个初始执行涉及,例如,打开文件或互联网连接,并且在创建流之后和使用任何值之前有很长的延迟,这可能是非常有问题的 - 您将最终得到一个打开的文件描述符坐你的互联网连接可能会超时,导致整个事情失败。

使用初始空流修复它的简单尝试不起作用:

def runiter(start: Int) {
  // Create a stream that returns successive integers on demand, e.g. 3, 4, 5, ....
  val iter = {
    def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1)
    Stream[Int]() ++ loop(start)
  }
  // Now, sometime later, we retrieve the values ....
  println("about to loop")
  for (x <- iter) {
    if (x < 10) println("saw value", x) else return
  }
}

结果(与之前相同):

scala> runiter(3)
(I computed a value,3)
about to loop
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)

但是,可以通过使用初始的空迭代器将流更改为迭代器来解决此问题,即使这种情况很明显:

def runiter(start: Int) {
  // Create an iterator that returns successive integers on demand, e.g. 3, 4, 5, ....
  val iter = {
    def loop(v: Int): Iterator[Int] = { println("I computed a value", v); Iterator(v)} ++ loop(v+1)
    Iterator[Int]() ++ loop(start)
  }
  // Now, sometime later, we retrieve the values ....
  println("about to loop")
  for (x <- iter) {
    if (x < 10) println("saw value", x) else return
  }
}

结果:

scala> runiter(3)
about to loop
(I computed a value,3)
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)

请注意,如果不添加初始的空迭代器,则会遇到与stream相同的过早执行问题。