Scala Streams 如何实现不变性?
How Immutability is Achieved in Scala Streams?
它可能会变得愚蠢,但我对以不可变方式进行 Scala Stream 评估有疑问。
假设我有一个这样的流(所有行都在 repl 中执行);
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = 流(1, ?)
当我 运行 以下几行时;
a(3);
a
我明白了;
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
我的第一个问题是这个不可变结构是如何改变的?我的意思是如果这样做(假设变量 'a' 定义为 'var');
a = a(3) 我可能会期待这样的结果。
我的另一个问题是当我 运行 以下几行时;
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = 流(1, ?)
val b = a;
b: scala.collection.immutable.Stream[Int] = 流(1, ?)
b(5);
scala.collection.immutable.Stream[Int] = 流(1, 2, 3, 4, 5, 6, ?)
a
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)
正如你在执行'a'后看到的最后一部分,它似乎又变了。
如果我尝试使用 List 类型进行这种赋值(据我所知,List 是 Stream 的严格版本)并进行一些转换,如 drop、take 等)
val a = List(1,2,3,4,5)
val b = a;
b.dropRight(1)
变量'a'和'b'仍然是List(1,2,3,4,5)
那么这是怎么发生的,我想念的重点是什么?
Scala Streams 提供 memoization - 它们就像惰性列表,但一旦生成元素,它们就会被存储以供将来检索。
因此,当您 "force" Stream b
通过请求索引 5 处的元素来评估其某些元素时,原始 Stream a
(这是同一个 Stream 对象)也是被逼的
关键点:这样做不会修改流(它保持不可变),它只是改变了哪些元素已经被评估和被记忆。
您的 Stream(1,?)
和 Stream(1,2,3,4,5,6,?)
是同一个流,只是评估的程度不同:
scala> val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val b = a
scala> a(3)
res9: Int = 4
scala> a
res10: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> b
res11: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> Stream(1,2,3,4,5,6,7,8,9,10) == a
res12: Boolean = true
scala> Stream(1,2,3,4,5,6,7,8,9,10) == b
res13: Boolean = true
它可能会变得愚蠢,但我对以不可变方式进行 Scala Stream 评估有疑问。
假设我有一个这样的流(所有行都在 repl 中执行);
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = 流(1, ?)
当我 运行 以下几行时;
a(3);
a
我明白了;
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
我的第一个问题是这个不可变结构是如何改变的?我的意思是如果这样做(假设变量 'a' 定义为 'var'); a = a(3) 我可能会期待这样的结果。
我的另一个问题是当我 运行 以下几行时;
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = 流(1, ?)
val b = a;
b: scala.collection.immutable.Stream[Int] = 流(1, ?)
b(5);
scala.collection.immutable.Stream[Int] = 流(1, 2, 3, 4, 5, 6, ?)
a
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)
正如你在执行'a'后看到的最后一部分,它似乎又变了。
如果我尝试使用 List 类型进行这种赋值(据我所知,List 是 Stream 的严格版本)并进行一些转换,如 drop、take 等)
val a = List(1,2,3,4,5)
val b = a;
b.dropRight(1)
变量'a'和'b'仍然是List(1,2,3,4,5)
那么这是怎么发生的,我想念的重点是什么?
Scala Streams 提供 memoization - 它们就像惰性列表,但一旦生成元素,它们就会被存储以供将来检索。
因此,当您 "force" Stream b
通过请求索引 5 处的元素来评估其某些元素时,原始 Stream a
(这是同一个 Stream 对象)也是被逼的
关键点:这样做不会修改流(它保持不可变),它只是改变了哪些元素已经被评估和被记忆。
您的 Stream(1,?)
和 Stream(1,2,3,4,5,6,?)
是同一个流,只是评估的程度不同:
scala> val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val b = a
scala> a(3)
res9: Int = 4
scala> a
res10: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> b
res11: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> Stream(1,2,3,4,5,6,7,8,9,10) == a
res12: Boolean = true
scala> Stream(1,2,3,4,5,6,7,8,9,10) == b
res13: Boolean = true