55

在 Scala 中,您可以为许多(所有?)类型的集合创建视图。

究竟什么是视图,视图对哪些目的有用?

4

4 回答 4

51

视图是集合的非严格版本。这意味着元素是在访问时计算的,而不是像在普通集合中那样急切地计算。

以以下代码为例:

val xs = List.tabulate(5)(_ + 1)
val ys = xs.view map { x => println(x); x * x }

只是这不会打印任何东西,但每次访问列表都会执行计算并打印值,即每次调用ys.head都会导致1打印。如果您想再次获得该系列的严格版本,您可以调用force它。在这种情况下,您将看到打印出的所有数字。

视图的一个用途是当您需要遍历一组计算成本很高的值并且一次只需要一个值时。视图还允许您通过调用toStream它们来构建惰性序列,这些序列也将缓存评估的元素。

于 2010-07-29T11:00:20.093 回答
15

一个用例是当您需要收集元素转换的第一个结果时:

    case class Transform(n: Int) { println("Transform "+n)}
    val list = List(1,2,3,4,5)
    list.view.map(v => Transform(v)).collectFirst{case Transform(3) => println("found")}

印刷:

Transform 1
Transform 2
Transform 3
found

尽管:

    list.map(v => Transform(v)).collectFirst{case Transform(3) => println("found")}

印刷:

Transform 1
Transform 2
Transform 3
Transform 4
Transform 5
found
于 2015-03-30T12:54:45.847 回答
9

请参阅来自Scala 2.8 Collections API的视图

默认情况下,Scala 集合在其所有转换器中都是严格的,除了Stream,它懒惰地实现其所有转换器方法。但是,有一种系统的方法可以将每个集合变成一个惰性集合,反之亦然,它基于集合视图。视图是一种特殊的集合,代表一些基本集合,但会延迟实现所有转换器。

...

您可能需要考虑使用视图的原因有两个。首先是性能。您已经看到,通过将集合切换到视图可以避免构建中间结果。这些节省可能非常重要。

...

第二个用例适用于可变序列的视图。此类视图上的许多转换器功能提供了进入原始序列的窗口,然后可以使用该窗口选择性地更新该序列的某些元素。

于 2010-12-15T20:22:13.757 回答
0

view 用于惰性计算,但不用于节省内存。

当您针对集合创建视图时,内存已经分配给集合。

在创建视图时val view = Range(1,9).view.,集合已经分配了内存,如果太大,比如Range(1,1000000000),,OOM是无法避免的

于 2018-05-10T22:56:53.620 回答