为什么 Swift 编译器会说,隐式异步调用非隔离函数返回的不可发送类型“X”不能跨越参与者边界?

问题描述 投票:0回答:1

我很好奇,有人可以帮我处理 swift 6 错误吗?考虑这段代码:

class Foo {
    init() async throws {}
}

struct ContentView: View {
    var body: some View {
        Button ("Test") {
            Task {
                let _ = try await Foo()
            }
        }
    }
}

如果项目的 Swift 语言版本设置为“Swift 6”(Xcode 16.0),则

let _ = ...
行会给出以下错误:

对非隔离函数隐式异步调用返回的不可发送类型“Foo”不能跨越参与者边界。

这是怎么回事?我已经知道如何使 Foo 可发送 - 这不是我正在寻找的。相反,我试图了解演员的情况。

我相信

Task
闭包将在
@MainActor
上运行。不知何故,异步初始化程序似乎导致我的
Foo
对象跨越参与者边界,但我不明白为什么。它可能与错误中引用的隐式调用有关。但这个隐式调用到底是什么?有人能给我指出一些解释这种情况的文档吗?

顺便说一句,我知道使任务分离可以解决这个问题。但我还是不明白到底发生了什么。

swift swift-concurrency swift-compiler
1个回答
0
投票

你说:

我相信

Task
闭包将在
@MainActor
上运行。

是的,

Task
与主要演员隔离。

但是

Foo
的初始化器不是。它是一个异步初始化程序,不与任何特定参与者隔离,因此它将在“通用执行程序”上运行。在
MainActor.preconditionIsolated()
的初始化器中添加一个
Foo
,你会发现它不在主角身上。这就是问题的根源,该对象正在协作线程池中的任意线程上初始化,并被发送回主要参与者,如果
Foo
不是
Sendable
,则无法执行此操作。

© www.soinside.com 2019 - 2024. All rights reserved.