构建 LazyList
构造惰性序列。
构建 LazyList 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
构建基础
构建 LazyList 有多种方式。最简单的是使用 apply 工厂方法,就像构建 List 一样。
不过,真正的强大之处在于那些能保持尾部惰性的构造方法,这正是本课要探索的内容。
val ll = LazyList(10, 20, 30)
println(ll.head)空的 LazyList
LazyList.empty 是终止项,是 Nil 的惰性等价形式。每个有限的 LazyList 都以它结束。
使用 #:: 添加元素时,可以将它作为基础情况。
object Demo extends App {
val empty = LazyList.empty[Int]
println(empty.isEmpty)
println(empty.toList)
}使用 #:: 添加元素
#:: 运算符会将头部添加到按名称传递的尾部。请从右到左构建列表,并以 LazyList.empty 结束。
由于 #:: 会惰性地接收尾部,因此在强制求值之前,头部之后的内容都不会构建。
object Demo extends App {
val ll = 1 #:: 2 #:: 3 #:: LazyList.empty
println(ll.toList)
}观察惰性求值
在尾部放入副作用,观察它何时运行。只有强制计算尾部时才会触发它。
运行这段代码:“building tail” 只有在访问第二个元素后才会打印,而不是在定义 LazyList 时打印。
object Demo extends App {
val ll = 1 #:: { println("building tail"); 2 #:: LazyList.empty }
println("defined")
println(ll.head)
println(ll(1))
}显式使用 cons
在底层,#:: 就是 LazyList.cons。在 cons 中,头部和尾部都按名称传递,从而可以完全控制求值时机。
定义递归生成器时,这种方式很有用。
val ll = LazyList.cons(1, LazyList.cons(2, LazyList.empty))
println(ll.head)递归生成器
LazyList 可以引用自身。您可以定义一个生成头部的函数,并递归调用自身来生成尾部。
由于尾部按名称传递,递归不会永远运行;它会暂停,直到相应的单元被请求。
def countFrom(n: Int): LazyList[Int] =
n #:: countFrom(n + 1)
println(countFrom(5).take(3).toList)运行生成器
让我们运行一个引用自身的生成器,并提取几个值。take 会限制被强制计算的单元数量。
没有 take 的话,计算会无限循环,因此在强制计算无限生成器之前,请始终为其设置边界。
object Demo extends App {
def countFrom(n: Int): LazyList[Int] =
n #:: countFrom(n + 1)
println(countFrom(1).take(5).toList)
}从迭代器构建
您可以包装已有的集合或迭代器。LazyList.from(start) 会构建一个无限计数序列,而 someList.to(LazyList) 会转换已知的数据。
这样,您就能以惰性方式查看已有的或可以描述的数据。
object Demo extends App {
val ll = List(1, 2, 3).to(LazyList)
println(ll.map(_ * 2).toList)
}LazyList.iterate
LazyList.iterate(seed)(f) 会反复将 f 应用于前一个元素,以构建下一个元素。
对于按照步进规则定义的序列(例如二的幂),这是一种清晰的表达方式。
object Demo extends App {
val powers = LazyList.iterate(1)(_ * 2)
println(powers.take(6).toList)
}LazyList.continually
LazyList.continually(expr) 会无休止地重复一个表达式,并为每个元素重新计算它。它适用于生成常量流或随机流。
请将它与 take 结合,以提取有限的一段。
object Demo extends App {
val zeros = LazyList.continually(0)
println(zeros.take(4).toList)
}选择构造方法
固定的小型列表请使用 apply;手写递归请使用 #:: 或 cons;步进规则请使用 iterate;计数请使用 from;重复生成请使用 continually。
它们都会保持尾部惰性,因此选择哪一种主要取决于表达的清晰度。
快速检查
请检查您对 LazyList 构建方式的掌握程度。
回顾
您使用 apply、empty、#::/cons、iterate、from 和 continually 构建了 LazyList。
按名称传递的尾部使得定义自引用的、可能无限的生成器变得安全。接下来,我们将利用这一点创建真正的无限流。
常见问题解答
「构建 LazyList」课时是免费的吗?
是的 — 「构建 LazyList」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
「构建 LazyList」这节课中我会学到什么?
构造惰性序列。 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「构建 LazyList」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?
能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。