我认为这个问题本质上是关于可变性中的懒惰。
在 Scala编程(或the docs)中,他们提供了有关如何在不可变和可变集合上使用视图的示例。在该部分中,他们声明
[ transformer 方法]将至少一个集合作为其接收者对象,并在其结果中产生另一个集合。 ... view 是一种特殊的集合,它代表一些基本集合,但是懒惰地实现了所有的转换器。
他们给出了具有不变集合的示例,我了解那里的懒惰是如何工作的。但是我在懒惰在可变集合的示例中扮演的角色很挣扎:
[在可变序列上的视图]上的许多转换器功能为原始序列提供了一个窗口...示例...
1) Solving TestCase-01.dat...
- UB = 48, LB = 48
- Status = 2
- Solve Time = 1.299999952 sec
该视图不会复制这些元素,而只是提供对它们的引用。
val arr = (0 to 9).toArray
val subarr = arr.view.slice(3, 6)
我理解为什么我们会得到这个答案。但是,关于变压器def negate(xs: collection.mutable.Seq[Int]) =
for (i <- 0 until xs.length) xs(i) = - xs(i)
negate(subarr)
arr // Array(0, 1, 2, -3, -4, -5, 6, 7, 8, 9)
的懒惰是什么?我已经理解惰性是指仅在需要时才计算值(例如不可变集合示例)。但是slice
中的值从未被计算过,它们只是对slice
中的值的引用,即使在调用arr
之后也是如此。这是我对懒惰的误解吗?还是文档以另一种方式使用懒惰?还是其他?
答案 0 :(得分:1)
此示例显示了slice
中的惰性内容:
val arr = (0 to 9).toArray
val subarrLazy = arr.view.map(x=>{println(x+1);x+1}).slice(3, 6)
//nothing printed
subarrLazy.force
//prints 1 2 3 ...
subarrLazy(0)
//prints: 3
subarrLazy
产生的map
中的值将仅按需计算。
编辑:
正如我现在看到的,在使用arr.view.slice(3, 6)
的情况下,没有什么要计算的,而且懒惰甚至不用于值计算,因此,在使用map的情况下,slice
只返回可变的seq而不是view
+切片。但是此序列仍然是按需延迟执行切片的惰性操作的包装。
val a: SeqView[Int, Array[Int]] = arr.view.map(x=>{println(x);x}).slice(3, 6)
val b: mutable.Seq[Int] = arr.view.slice(3, 6)
所以我们可以说涉及两种惰性:1.值计算上的惰性2.变压器上的惰性。不幸的是,我不知道这些类型的正式名称以及它们之间的关系。我猜想#1只是函子延迟映射其值的一种特例(例如IO monad),而#2是延迟链模式或类似的东西。
这两种模式都与可变性无关。
答案 1 :(得分:0)
这是这种懒惰行为的一个更好的例子:
val a = Array(1,2,3)
val b = a.map(_ + 5)
val c = a.view.map(_ + 5)
println(b(1)) //prints 7
println(c(1)) // prints 7
a(1) = 5
println(b(1)) // still prints 7, since that array was computed on instantiation
println(c(1)) // now prints 10, since elements of c are lazily evaluated each time.