前言
AsyncSequence
是并发性框架和 SE-298 提案的一部分。它的名字意味着它是一个供给异步、顺序和迭代访问其元素的类型。换句话说:它是咱们在 Swift 中了解的惯例序列的一个异步变体。
就像你不会常常创立你的自界说序列相同,我不期望你常常创立一个自界说的 AsyncSequence
完结。然而,因为与 AsyncThrowingStream和AsyncStream
等类型一同运用,你很或许不得不与异步序列一同作业。因而,我将辅导你运用 AsyncSequence
实例进行作业。
什么是 AsyncSequence?
AsyncSequence
是咱们在Swift中了解的 Sequence
的一个异步变体。因为它的异步性,咱们需要运用 await
关键字,因为咱们要处理的是异步界说的办法。如果你没有运用过 async/await
,我鼓励你阅览我的文章:Swift 中的async/await ——代码实例详解
值能够随着时间的推移而变得可用,这意味着一个 AsyncSequence
在你第一次运用它时或许不包括也或许包括一些,或许全部的值。
重要的是要理解 AsyncSequence
只是一个协议。它界说了怎么访问值,但并不发生或包括值。AsyncSequence
协议的完结者供给了一个 AsyncIterator
,并担任开发和潜在地存储值。
创立 AsyncSequence
创立一个自界说的 AsyncSequence。
为了更好地理解 AsyncSequence
是怎么作业的,我将演示一个完结实例。然而,在界说你的 AsyncSequence
的自界说完结时,你或许想用 AsyncStream
来代替,因为它的设置更方便。因而,这只是一个代码比如,以更好地理解 AsyncSequence
的作业原理。
下面的比如沿用了原始提案中的比如,完结了一个计数器。这些值能够立即运用,所以对异步序列没有太大的需求。然而,它的确展示了一个异步序列的基本结构:
struct Counter: AsyncSequence {
typealias Element = Int
let limit: Int
struct AsyncIterator : AsyncIteratorProtocol {
let limit: Int
var current = 1
mutating func next() async -> Int? {
guard !Task.isCancelled else {
return nil
}
guard current <= limit else {
return nil
}
let result = current
current += 1
return result
}
}
func makeAsyncIterator() -> AsyncIterator {
return AsyncIterator(howHigh: limit)
}
}
如您所见,咱们界说了一个完结 AsyncSequence
协议的 Counter
结构体。该协议要求咱们返回一个自界说的 AsyncIterator
,咱们运用内部类型处理了这个问题。咱们能够决定重写此示例以消除对内部类型的需求:
struct Counter: AsyncSequence, AsyncIteratorProtocol {
typealias Element = Int
let limit: Int
var current = 1
mutating func next() async -> Int? {
guard !Task.isCancelled else {
return nil
}
guard current <= limit else {
return nil
}
let result = current
current += 1
return result
}
func makeAsyncIterator() -> Counter {
self
}
}
咱们现在能够将 self
作为迭代器返回,并保持所有逻辑的会集。
注意,咱们有必要通过供给 typealias 来协助编译器遵守 AsyncSequence
协议。
next()
办法担任对全体数值进行迭代。咱们的比如归结为供给尽或许多的计数值,直到咱们到达极限。咱们通过对 Task.isCancelled
的查看来完结撤销支撑。
异步序列的迭代
现在咱们知道了什么是 AsyncSequence
以及它是怎么完结的,现在是时分开始迭代这些值了。
以上述比如为例,咱们能够运用 Counter
开始迭代:
for await count in Counter(limit: 5) {
print(count)
}
print("Counter finished")
// Prints:
// 1
// 2
// 3
// 4
// 5
// Counter finished
咱们有必要运用 await
关键字,因为咱们或许会异步接纳数值。一旦不再有预期的值,咱们就退出for循环。异步序列的完结者能够通过在 next()
办法中返回 nil
来表明到达极限。在咱们的比如中,一旦计数器到达装备的极限,或许迭代撤销,咱们就会到达这个预期:
mutating func next() async -> Int? {
guard !Task.isCancelled else {
return nil
}
guard current <= limit else {
return nil
}
let result = current
current += 1
return result
}
许多惯例的序列操作符也可用于异步序列。其结果是,咱们能够以异步的方式执行映射和过滤等操作。
例如,咱们能够只对偶数进行过滤:
for await count in Counter(limit: 5).filter({ $0 % 2 == 0 }) {
print(count)
}
print("Counter finished")
// Prints:
// 2
// 4
// Counter finished
或许咱们能够在迭代之前将计数映射为一个 String
:
let counterStream = Counter(limit: 5)
.map { $0 % 2 == 0 ? "Even" : "Odd" }
for await count in counterStream {
print(count)
}
print("Counter finished")
// Prints:
// Odd
// Even
// Odd
// Even
// Odd
// Counter finished
咱们甚至能够运用 AsyncSequence
而不运用for循环,通过运用 contains
等办法。
let contains = await Counter(limit: 5).contains(3)
print(contains) // Prints: true
注意,上述办法是异步的,意味着它有或许无休止地等候一个值的存在,直到底层的 AsyncSequence
完结。
结论
AsyncSequence
是咱们在Swift中了解的惯例 Sequence
的异步替代品。就像你不会常常自己创立一个自界说 Sequence
相同,你也不太或许创立自界说的异步序列。
本文正在参加「金石计划 . 分割6万现金大奖」