我有一个异步函数队列,如下所示:
class Queue {
var queue: [() async -> Void] = []
func enqueue(_ operation: @escaping () async -> Void) {
queue.append(operation)
}
}
你可以这样使用它:
func networkCall() async {
Task.sleep(2)
}
let queue = Queue()
queue.enque(networkCall)
我想用类似的方式来尝试对一个带有如下参数的函数进行enque:queue.enque(networkCall(duration: 2))
为此,我必须将@autoclosure
属性添加到enqueue(_:)
函数中,如下所示:
func enqueue(_ operation: @autoclosure @escaping () async -> Void) {
// ...
}
但这导致了一个错误:'async' autoclosure parameter in a non-'async' function
.
我的问题是,为什么会出现这个错误?自动闭包也在转义,所以它不会在enque函数中执行,那么为什么编译器会在意它没有标记为async
?我还想知道是否有任何修复方法,以便为我的enqueue函数实现类似queue.enque(networkCall(duration: 2))
的函数调用。
先谢了。
1条答案
按热度按时间jgwigjjp1#
当然,将转义的异步自动闭包作为非异步函数的参数在技术上并没有什么问题,但Swift仍然会因为“风格”原因而阻止您这样做。
想想你会如何称呼
enqueue
,你 * 不能 * 用你喜欢的方式称呼它:相反,您需要执行以下操作:
因为Swift Concurrency的基本原则之一是所有挂起点都用
await
标记,就像每个可能发生错误的地方都用try
标记一样。尝试实际地使
enqueue
异步,并亲自查看它-您必须编写因此,如果
enqueue
不是异步的,那么这意味着类似queue.enqueue(await networkCall(duration: 2))
的东西可能会出现在非异步代码中。**您最终会看到await
* 似乎 * 出现在非异步代码中。**当然,这在本质上是不正确的,但它仍然令人惊讶,需要读者查看enqueue
的定义,才能看到它实际上是一个自动闭包。事实上,some people argue即
@autoclosure
根本不应该与@escaping
一起使用(没有任何异步操作),因为自动创建的闭包可能会意外地捕获self
并创建一个保留循环。我建议使用非自动闭包,语法只是
()
与{}
的问题:无论是否取消此限制,您都需要
await
。