构建自定义惰性序列
创建您自己的惰性求值序列。
构建自定义惰性序列 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。
为什么要自定义惰性序列
除了 map 和 filter,您还可以构建自己的惰性求值序列,用于无限生成器或昂贵的计算流,让它们按需运行。
LazySequence 类型
调用 .lazy 会将集合包装为符合 LazySequenceProtocol 的类型。您添加的操作会返回更多惰性包装器:
let view = [1, 2, 3].lazy
let mapped = view.map { $0 * 2 }
print(Array(mapped)) // [2, 4, 6] -- LazyMapSequence基于拉取的序列
自定义序列基于拉取:迭代器每次被调用时,只会在需要时计算下一个值。下面是一个 Fibonacci 生成器:
struct Fibonacci: Sequence, IteratorProtocol {
var a = 0, b = 1
mutating func next() -> Int? {
let r = a
(a, b) = (b, a + b)
return r
}
}
print(Array(Fibonacci().prefix(6))) // [0, 1, 1, 2, 3, 5]无限序列,惰性消费
由于值是按需拉取的,只要截取有限的一部分,无限序列就是安全的:
struct Naturals: Sequence, IteratorProtocol {
var n = 1
mutating func next() -> Int? { defer { n += 1 }; return n }
}
print(Array(Naturals().prefix(4))) // [1, 2, 3, 4]符合 LazySequenceProtocol
采用 LazySequenceProtocol 后,您自己的类型也可以通过 map/filter 进行惰性链式处理:
struct Counter: Sequence, IteratorProtocol, LazySequenceProtocol {
var n = 0; let limit: Int
mutating func next() -> Int? {
guard n < limit else { return nil }
defer { n += 1 }
return n
}
}
print(Array(Counter(n: 0, limit: 3).map { $0 * 10 })) // [0, 10, 20]sequence(first:next:)
标准库提供了一个构建器,无需新建类型即可创建自定义惰性序列:
let powers = sequence(first: 1) { $0 <= 16 ? $0 * 2 : nil }
print(Array(powers)) // [1, 2, 4, 8, 16, 32]sequence(state:next:)
在各个步骤之间传递更丰富的状态:
let fibs = sequence(state: (0, 1)) { (s: inout (Int, Int)) -> Int? in
let r = s.0
s = (s.1, s.0 + s.1)
return r
}
print(Array(fibs.prefix(6))) // [0, 1, 1, 2, 3, 5]AnySequence 包装器
对外提供接口时,可以使用 AnySequence 隐藏具体类型:
func evens(upTo n: Int) -> AnySequence<Int> {
AnySequence((0...n).lazy.filter { $0 % 2 == 0 })
}
print(Array(evens(upTo: 8))) // [0, 2, 4, 6, 8]惰性计算流
将昂贵的工作延迟到每个元素真正被消费时再执行:
let stream = (1...5).lazy.map { (n: Int) -> Int in
print("computing \(n)")
return n * n
}
print(stream.first!) // computing 1, then 1停止生成器
从 next() 返回 nil,即可干净地结束序列:
let countdown = sequence(state: 3) { (s: inout Int) -> Int? in
guard s > 0 else { return nil }
defer { s -= 1 }
return s
}
print(Array(countdown)) // [3, 2, 1]整合起来
将自定义生成器与惰性操作组合起来,构建按需运行的管道:
let primesIsh = sequence(first: 2) { $0 < 20 ? $0 + 1 : nil }
.lazy
.filter { n in (2..<n).allSatisfy { n % $0 != 0 } }
print(Array(primesIsh)) // [2, 3, 5, 7, 11, 13, 17, 19]快速检查
什么信号表示自定义 IteratorProtocol 序列已经结束?
回顾
您已经了解了自定义惰性序列:
.lazy会生成LazySequenceProtocol包装器- 实现
Sequence+IteratorProtocol;next()返回nil以停止序列 - 使用
sequence(first:next:)/sequence(state:next:)作为快速构建器 - 使用
AnySequence进行包装,以隐藏具体类型
课程完成!下一步:深入学习闭包。
常见问题解答
「构建自定义惰性序列」课时是免费的吗?
是的 — 「构建自定义惰性序列」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。
「构建自定义惰性序列」这节课中我会学到什么?
创建您自己的惰性求值序列。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Swift Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「构建自定义惰性序列」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Swift Academy 课中编写并运行代码吗?
能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- lazy 属性
- 惰性 map 与 filter
- 惰性与即时求值的权衡
- 构建自定义惰性序列