我编写这个扩展是为了在等待多个异步任务并行时简化代码.

extension Task{
    static func race<T>(_ tasks:[() async throws -> T]) async throws -> T
    {
        return try await withThrowingTaskGroup(of: T.self) { taskGroup in
            for task in tasks {
                taskGroup.addTask(operation: task)
            }
            let first = try await taskGroup.next()
            taskGroup.cancelAll()
            return first!
        }
    }
    
    static func all<T>(_ tasks:[() async throws -> T]) async throws -> [T]
    {
        return try await withThrowingTaskGroup(of: T.self) { taskGroup in
            for task in tasks {
                taskGroup.addTask(operation: task)
            }
            return try await taskGroup.collectAsArray()
        }
    }
}

extension AsyncSequence{
    func collectAsArray() async rethrows -> [Element]
    {
        var results: [Element] = []
        for try await result in self
        {
            results.append(result)
        }
        return results
    }
}

但我得到Generic parameter 'Failure' could not be inferredGeneric parameter 'Success' could not be inferred错误时,使用它们

let x = try await Task.race([{return 1},{return 2}])
let y = try await Task.all([{return 1},{return 2}])

因此,我必须通过显式指定返回类型来消除错误

let x = try await Task<Int,Error>.race([{return 1},{return 2}])
let y = try await Task<Int,Error>.all([{return 1},{return 2}])

有没有可能让它自动推断返回类型和错误类型,这样我就不需要显式地编写它们?

推荐答案

您可以查看一下Task上的其他静态方法是如何声明的,例如sleep.它们都对Success和/或Failure类型参数有约束.例如,sleep要求SuccessFailure都是Never.您的静态方法也可以做到这一点.

您可以只重用现有的Success类型参数,而不是声明额外的类型参数T.然后,您可以要求Failure类型参数为Never(或任何其他Error类型-无论是哪种类型).

此外,这些方法应该使用@Sendable个闭包才是完全安全的.调用者还必须传递@Sendable个闭包.

extension Task where Failure == Never {
    static func race(_ tasks: [@Sendable () async throws -> Success]) async throws -> Success
    {
        return try await withThrowingTaskGroup(of: Success.self) { taskGroup in
            for task in tasks {
                taskGroup.addTask(operation: task)
            }
            let first = try await taskGroup.next()
            taskGroup.cancelAll()
            return first!
        }
    }
}

以这种方式获取数组会使SWIFT无法推断调用点的@Sendable,因此您必须明确指定它:

try await Task.race([
    { @Sendable in await doSomething() },
    { @Sendable in await doSomeOtherThing() }
])

我建议添加一个使用varargs的重载:

static func race(_ tasks: (@Sendable () async throws -> Success)...) async throws -> Success
try await Task.race(
    { await doSomething() },
    { await doSomeOtherThing() }
)

Swift相关问答推荐

为什么Swift在某些链调用中不能对不可变值使用变异成员,而在其他链调用中则不能使用变异成员?

为表单部分赋予背景 colored颜色 /渐变

如何在HStack中均匀分布视图?

有没有一种方法可以迭代可编码的代码(例如,JSON解析中的每一项)?

如何将新事例添加到枚举中?

Swift通过设置变量B自动设置变量A的值

当字符串包含 \r\n 时,NSRegularExpression 不起作用

Swift 并发任务与调度队列线程:是什么决定同时运行多少任务?

在 RealmSwift 中表示范围值?

如何自己实现同一个 iOS 16 锁屏圆形小部件?

用逻辑运算符保护让

闭包 - deinit self 对象的时间

将基于MyProtocol的泛型函数的参数更改为使用存在的any MyProtocol或some MyProtocol是否会受到惩罚?

在 xcode 13 中的构建之间保持可访问性权限

如何防止 UITableViewCell 移动(Swift 5)

当我必须在 Swift 中的类、 struct 和枚举之间进行 Select 时,我应该如何推理?

在 Xcode 中自动实现 Swift 协议方法

如何更改弹出框的大小

UICollectionView 自定义单元格在 Swift 中填充宽度

如何在 SwiftUI 中创建带有图像的按钮?