为什么我的不可Send的闭包能够跨越隔离边界?

移动开发 2026-07-10

我有这段代码

actor MyActor {

  var checker: @MainActor () -> Void = {}

  init(checker: @escaping @MainActor () -> Void) {
    self.checker = checker
  }

  nonisolated func noniso() {
    Task {
      let checker = await self.checker
      await checker()
    }
  }
}

这段代码在Swift 6中可以正常编译,这有点奇怪,因为 checker 不是一个 @Sendable闭包。

noniso 函数调用Task {},这会创建一个非隔离的异步上下文。然后 checker 将边界从 MyActor 传递到非隔离上下文。然后当我调用它时,它再次把边界从非隔离上下文传递回MainActor(因为它被标记为 @MainActor)。

这有点奇怪,因为我本来预期这两行都会失败,原因是 checker 不是 @Sendable

解决方案

SE-0434@Sendable 会被推断用于全局actor隔离的闭包。

“Motivation” 小节提到了一个与你描述的情形极为相似的情况。

接下来,在当前并发规则下,函数类型可能同时对全局actor隔离,同时又不要求是 Sendable

func test(globallyIsolated: @escaping @MainActor () -> Void) { Task { // error: capture of 'globallyIsolated' with non-sendable type '@MainActor () -> Void' in a `@Sendable` closure await globallyIsolated() } }

这不是一个有用的组合:这样的函数只有在当前上下文对全局actor隔离时才可以使用,在那种情况下,全局actor注解就显得多余,因为所有非 Sendable 的函数都会在全局actor隔离下运行。更好的做法是让全局actor属性始终隐含 @Sendable

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章