我怎么能表明我想要一个函数的同步版本时,在异步上下文中Swift?



如果你在Swift中使用结构化并发,并且在异步上下文中,编译器会假设如果存在一个异步版本的函数,那就是你想要使用的。有没有办法告诉它你想要同步版本?

下面是一个例子(并表明这至少在理论上是可能的)

在香草SpriteKit中,如果你有一个SKNode和这些行:

node.run(SKAction.rotate(byAngle: -1.5*CGFloat.pi, duration: 6))
node.run(SKAction.scale(by: 25, duration: 6))

节点将同时在6秒的时间内旋转和缩放。

…如果您正在使用结构化并发,run将使用该函数的异步版本和所需的代码:

await node.run(SKAction.rotate(byAngle: -1.5*CGFloat.pi, duration: 6))
await node.run(SKAction.scale(by: 25, duration: 6))

将导致节点旋转6秒,然后缩放6秒。completion回调被异步风格的流控制所取代。

问题是我不想让它等待并返回,但是我不知道有什么方法可以说"嘿——就使用这个函数的同步版本吧"。如果我只是省略await,这是一个编译错误。

为了证明这是可能的,我可以强制使用函数的同步版本,如下所示:

node.run(SKAction.rotate(byAngle: -1.5*CGFloat.pi, duration: 6)){}
node.run(SKAction.scale(by: 25, duration: 6)){}

…提供结束尾随闭包。所以run的同步版本没有什么特别之处。这是有效的,但是没有其他的方法来说"只使用同步功能"吗?

我也可以这样做:

Task{ await node.run(SKAction.rotate(byAngle: -1.5*CGFloat.pi, duration: 6))}
Task{ await node.run(SKAction.scale(by: 25, duration: 6)) }

…但这似乎更麻烦。

那么——底线——在Swift中,当你使用结构化并发时,当一个函数同时有同步和异步版本时,你如何表明你想使用同步版本?

在async函数内部,编译器更倾向于使用重载方法的async变体。有几种方法可以说服它使用非异步函数。

假设我们有一个重载函数foo:

func foo() {}
func foo() async {}

选择同步函数的第一种方法是闭包。在闭包内部,编译器更倾向于调用同步函数:

func barl() async {
{ foo() }()
}

我们还可以使用as:

指定我们想要的函数。
func bar2() async {
(foo as () -> _)()
}

为完整起见,我们还可以使用闭包选择同步函数,然后调用闭包获取该函数,然后调用该函数:

func bar3() async {
{ foo }()()
}

我更喜欢第一个解决方案,因为其他两个在调用时丢失了命名参数。我们可以将其推广为一个辅助函数:

func sync<T>(block: () -> T) -> T {
block()
}

使用这个帮助器,我们可以明确要求同步调用:

func bar() async {
sync { foo() }
}

最新更新