Streams,Views(SeqView)和Iterators在Scala中有哪些差异? 这是我的理解:
- 它们都是惰性列表。
- Streams缓存值。
- 迭代器只能使用一次? 不能回到开头重新计算值?
- View的值不被缓存,但可以多次评估?
因此,如果我想要节省堆空间,是否应该使用迭代器(如果我不会再次遍历列表)或视图? 谢谢。
Streams,Views(SeqView)和Iterators在Scala中有哪些差异? 这是我的理解:
因此,如果我想要节省堆空间,是否应该使用迭代器(如果我不会再次遍历列表)或视图? 谢谢。
首先,它们都是非严格的。这在函数相关的特定数学含义上有所体现,但基本上意味着它们是按需计算而不是提前计算。
Stream
确实是一个延迟列表。事实上,在Scala中,Stream
是一个List
,其tail
是一个lazy val
。一旦计算完成,值就会保留并被重复使用。或者说,这些值被缓存了。
Iterator
只能使用一次,因为它是指向集合的遍历指针,而不是集合本身。在Scala中,它的特殊之处在于您可以应用转换(例如map
和filter
)并仅获取新的Iterator
,该新的Iterator
只会在请求下一个元素时应用这些转换。
Scala以前提供过可重置的迭代器,但这很难以一般方式支持,因此它们没有包含在版本2.8.0中。
视图类似于数据库视图,意为将一系列变换应用于集合以生成“虚拟”集合。正如您所说,每次需要从中获取元素时,所有变换都会被重新应用。
迭代器和视图都具有出色的内存特性。Stream
很好用,但在Scala中,它的主要优点是编写无限序列(尤其是递归定义的序列)。不过,通过确保您不保留对其head
的引用(例如,通过使用def
而不是val
来定义Stream
),您可以避免将整个Stream
保存在内存中。
由于视图所带来的惩罚,通常应在应用转换后force
它,或者如果只需要从视图中提取少量元素,则应将其保留为视图,相较于视图的总大小。
Iterator
对于探索无限长度的数据也非常方便,通常情况下我更喜欢使用它们而不是 Stream
。在 Stream
中的真正好处在于先前访问过的值被缓存,这对于实现诸如斐波那契数列之类需要使用以前的值来定义的算法非常有用。 - Kevin Wright