Swift中自定义异步序列实现:固定与动态幂次场景
实现异步幂次序列的两种方案
一、固定幂次(平方、立方、四次方)的异步序列
实现思路
把输入数组转为异步序列,对每个元素异步计算指定幂次,再通过flatMap扁平化所有子序列,最终返回包含所有结果的AsyncSequence。
代码实现
// 扩展Collection,将普通数组转为AsyncSequence extension Collection { var async: AsyncStream<Element> { AsyncStream { continuation in for element in self { continuation.yield(element) } continuation.finish() } } } // 生成固定幂次的异步序列 func fixedPowerSequence(for numbers: [Int]) -> some AsyncSequence where Element == Int { numbers.async.flatMap { number in AsyncStream { continuation in Task { // 异步计算平方 let square = number * number continuation.yield(square) await Task.sleep(nanoseconds: 100_000_000) // 模拟异步耗时操作 // 异步计算立方 let cube = square * number continuation.yield(cube) await Task.sleep(nanoseconds: 100_000_000) // 异步计算四次方 let fourthPower = cube * number continuation.yield(fourthPower) continuation.finish() } } } } // 测试代码 Task { let result = await Array(fixedPowerSequence(for: [2, 3, 4])) print(result) // 输出: [4, 8, 16, 9, 27, 81, 16, 64, 256] }
二、随机幂次(x1到xk,k随机)的异步序列
实现思路
和固定幂次逻辑类似,但每个元素的幂次上限k是在异步计算过程中动态生成的(可模拟从外部接口获取或本地随机),再根据生成的k依次计算并返回对应幂次结果。
代码实现
// 模拟异步获取随机k的函数(实际场景可替换为API请求等) func fetchRandomPowerLimit(for number: Int) async -> Int { await Task.sleep(nanoseconds: 50_000_000) // 模拟异步获取耗时 return Int.random(in: 1...5) // 随机生成1-5之间的k值 } // 生成随机幂次的异步序列 func randomPowerSequence(for numbers: [Int]) -> some AsyncSequence where Element == Int { numbers.async.flatMap { number in AsyncStream { continuation in Task { // 异步获取当前数字对应的随机幂次上限k let k = await fetchRandomPowerLimit(for: number) // 依次计算x^1到x^k并返回 var currentPower = number // 初始为x^1 for _ in 1...k { continuation.yield(currentPower) await Task.sleep(nanoseconds: 100_000_000) // 模拟计算耗时 currentPower *= number } continuation.finish() } } } } // 测试代码 Task { for await value in randomPowerSequence(for: [2, 3, 4]) { print(value) // 示例输出: 2, 4, 8, 3, 9, 4, 16, 64(每次运行结果因k随机而不同) } }
关键细节说明
- AsyncStream:用于创建自定义异步序列,通过
continuation.yield()输出元素,continuation.finish()结束序列。 - flatMap:将每个元素对应的子异步序列扁平化为一个全局序列,实现结果的连续输出。
- 异步惰性执行:
AsyncSequence是惰性的,只有当开始遍历(如for await...in或转为Array)时,才会触发内部的异步计算逻辑。 - 错误处理:若需处理异步任务中的错误,可将
AsyncStream替换为AsyncThrowingStream,并在出错时调用continuation.finish(throwing: error)。
内容的提问来源于stack exchange,提问作者goofy4224
相关产品推荐
相关产品推荐

