正如您在对马特的评论中指出的那样,这种基本方法可能不是您想要的。这总是会启动两个请求,因此总是必须等待两个请求都完成才能返回(即使您从不需要它们两个)。
你可以通过这种方式得到你想要的东西,但它非常混乱(这就是为什么我怀疑他们还没有集成它):
创建一个新的运算符 ¿¿ 组合异步操作:
precedencegroup AsyncNilCoalescingPrecedence {
associativity: right
higherThan: NilCoalescingPrecedence
}
infix operator ¿¿ : AsyncNilCoalescingPrecedence
public func ¿¿<T>(optional: T?, defaultValue: () async throws -> T?) async rethrows -> T? {
if let result = optional { return result } else { return try await defaultValue() }
}
您的默认值应该在一个闭包中,因此它不会自动运行:
let langRes = try await traverse(file: languageFile, for: string)
let engRes = { try await traverse(file: englishFile, for: string) }
然后你可以做你想做的事(返回一个字符串):
let result = try await langRes ¿¿ engRes ?? "default"
也就是说,我想说的是,任何试图用类似 ?? 的操作符来解决这个问题的东西最终都会变得非常微妙,并且很容易意外地启动你不想要的任务。以马特的方式编写它可以更加明显地表明您正在做的事情实际上是错误的。
另一种类似的方法是:
let result: String
if let r = try await traverse(file: languageFile, for: string) { result = r }
else if let r = try await traverse(file: englishFile, for: string) { result = r }
else { result = "default" }
也就是说,我可能会考虑只提取一个循环:
func traverse(files: [URL], for string:String) async throws -> String {
for file in files {
if let result = try await traverse(file: file, for: string) { return result }
}
return "default"
}
let result = traverse([langRes, englishRes], for: string)
我相信应该可以创建类似的东西:
let result = try await [langRes, englishRes].lazy
.compactMap({try await traverse($0, for: string)})
.first ?? "default"
但我不认为 AsyncSequence 还没有添加很多扩展。IMO,用async
闭包映射序列应该创建一个 AsyncMapSequence。但目前还没有。此外,感觉应该可以调用first
AsyncSequence,但这也是不可能的(你必须调用first(where: {true})
或类似的愚蠢的东西,据我所知)。
(同意马特这是一个很好的问题。这值得在 Swift 论坛上讨论。这种事情应该有一个清晰的模式。)