继续上一节的话题,我们聊聊 async
对 closure 定义的影响。相比函数,这部分内容就少多了。还是继续之前 Dinner
的例子,我们给它添加一个自动煮饭的方法 cook
:
func cook(_ process: () async -> Void) async {
await process()
}
然后,调用的时候,我们就可以这样:
await dinner.cook { () async -> Void in
await dinner.chopVegetable()
try? await dinner.marinateMeat()
await dinner.preheatOven()
}
或者这样:
await dinner.cook {
await dinner.chopVegetable()
try? await dinner.marinateMeat()
await dinner.preheatOven()
}
这个简单的例子,就几乎包含所有和异步 closure 用法有关的内容了。我们一个个来看下。
首先,我们用 () async -> Void
这种形式让 cook
接受一个异步 closure 作为参数。这和定义一个异步函数的形式是类似的。但要强调下的是,接受异步 closure 作为参数的函数自身,也必须是一个异步函数。这个很好理解,因为在 cook
实现的内部,我们肯定要调用 process
,而异步函数只有在异步环境中才可以调用,因此 cook
必须是异步函数。
其次,当我们要显式定义一个 async
closure 的时候,可以像这样:
{ () async -> Void in
// asynchronous closure
}
直接把 closure 的类型写在 {}
里。但这并不是必须的。就像第二个调用 cook
的例子,我们可以省略 closure 的类型,一旦 closure 里包含 await
语句,Swift 编译器就会自动把这个 clousre 标记为异步的。但要注意的是,这个推断只会自动应用到直接包含 await
语句的 closure,如果存在 closure 嵌套的话,其它外层的 closure 仍旧是同步的。
What's next?
实际上,cook
的调用还有第三种方法,像这样:
func myCook() async {
print("My own cooking approach.")
}
await dinner.cook(myCook)
但为什么我们刚才没有提到呢?其实,说到现在,我们一直都在有意弱化和 await
相关的内容,在不影响理解的情况下,我们只是把它当成了一个可以跑通程序必须要使用的工具而已。在下段视频里,我们就正式和大家介绍 await
的用法以及和 await
有关的一个概念:suspension point。