Swift:能否从异步抛出函数返回异步抛出函数,无需try! await?
Swift异步抛出函数转发的正确写法
核心结论
- 绝对不要用
try! await:这会直接忽略函数抛出的错误,一旦发生错误会导致程序崩溃,完全不是最佳实践。 - 转发异步抛出函数的调用结果时,必须用
try await等待任务完成并正确传递错误。
错误写法分析
- 直接返回异步函数调用:
func bar() async throws -> Bool { return foo() // 报错:Call can throw but is not marked with 'try' }
原因:foo()是async throws类型的函数,调用它需要await等待异步任务完成,同时必须用try处理或传递抛出的错误,不能直接返回未执行的异步任务。
- 返回类型不匹配的函数调用结果:
func bar() async throws -> (() async throws -> Bool) { return foo() // 报错:Cannot convert return expression of type 'Bool' to return type '() async throws -> Bool' }
原因:foo()是调用后的异步任务结果(最终类型为Bool),而返回类型要求的是未执行的异步函数,这里应返回函数本身foo而非调用结果。但这种写法对带参数的函数(如baz(_ some: Int))不适用,因为baz(12)是调用后的结果,不是函数本身。
正确的转发写法
1. 直接转发调用结果(最常用场景)
如果bar()的目的是调用foo()并返回其结果,同时向上传递错误,正确写法是:
func foo() async throws -> Bool { return true } func bar() async throws -> Bool { return try await foo() }
这样bar()会等待foo()执行完成,若foo()抛出错误,bar()会将错误继续抛出给上层调用者处理,既安全又简洁。
2. 返回包装后的异步函数(针对带参数的场景)
如果需要bar()返回一个可执行的异步函数(比如包装baz(12)的调用),可以用闭包封装:
func baz(_ some: Int) async throws -> Bool { return true } func bar() async throws -> (() async throws -> Bool) { return { try await baz(12) } }
返回的闭包会在被调用时执行baz(12),并正确处理异步和错误逻辑。
总结
- 普通的调用转发用
try await即可,这是安全且符合Swift错误处理规范的最佳实践。 - 若需要返回异步函数而非调用结果,用闭包封装带参数的函数调用即可解决类型不匹配问题。
内容的提问来源于stack exchange,提问作者I'm Joe Too
相关产品推荐
相关产品推荐

