首页 文章

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

提问于
浏览
33

还有其他问题,如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 回答

  • 33

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

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

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

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

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

  • 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相同的过早执行问题 .

相关问题