/* Page prose (zh-Hans) */
"NonSendableProblem" = "# 为什么可变的类不是 Sendable，以及如何修复它\n\n现在来看这个整个协议之所以存在、正是为了捕捉的情形。想象一个为咖啡吧每日订单计数用的共享记分牌：一个类，因为我们想要一个人人都更新的对象：\n\n```swift\nfinal class OrderCount {\n    var total = 0\n}\n\nlet orders = OrderCount()\n\n// Hand the shared object to work running off the main actor:\nTask.detached {\n    orders.total += 1   // will not compile in Swift 6\n}\nprint(orders.total)\n```\n\n在 Swift 6 的语言模式下，这**无法编译。**错误是：*\"non-Sendable type 'OrderCount' of let 'orders' cannot exit main actor-isolated context\"*，还附带一条说明，指出 `OrderCount` *\"does not conform to the `Sendable` protocol.\"* 编译器看到一个可变的类即将被交给另一个隔离域，就在竞争可能发生*之前*拦住你。这就是相对于经典模型的转变：[并发的陷阱](Concurrency%20Hazards.playgroundchapter/Overview)一章里的 data race 是一个你必须去推理的运行时意外；而在这里它是一个你不可能错过的编译错误。\n\n* callout(试一试): 想象把上面的 `Task.detached` 改成一个普通的 `Task { }`。代码会编译通过吗？（会的；下一个 callout 解释原因。）\n\n* callout(为什么它能编译): 顶层代码，比如一个 Playground 页面，运行*在 main actor 上*。一个普通的 `Task { }` 会**继承**那份 main actor 隔离，所以对象从不离开它的域，代码实际上就能编译。`Task.detached` 运行*在* main actor *之外*，而那次边界跨越正是让共享一个可变的类变得不安全的原因。这里的教训是：危险出现在可变状态**在域之间跨越**的时候，所以那正是编译器安放绊线的地方。\n\n你有三种诚实的方式来修复它：\n\n**1. 把它变成一个 actor**（当状态必须保持可变且共享时最好）：";
"NonSendableFixes" = "actor 是自动 Sendable 的；那就是它们的职责。共享一个 actor 总是安全的，因为 actor 会把每一次访问串行化。\n\n**2. 把它变成不可变的**（当值在创建之后永不改变时最好）：\n\n```swift\nfinal class FrozenReceipt: Sendable {\n    let id: Int\n    let total: Int\n    init(id: Int, total: Int) {\n        self.id = id\n        self.total = total\n    }\n}\n```\n\n`final` + 全是 `let` + Sendable 成员 = 一个你可以安全共享的类，因为没有什么可以修改。\n\n**3. 把它隔离到一个 actor**（包括 `@MainActor`）：\n\n用一个全局 actor 标记这个类型，这样所有访问就已经汇集到一个域，这正是 `BalanceDisplay` 之前所做的。\n\n还有一个逃生舱口，`@unchecked Sendable`，在其中*由你*保证这个类型是安全的（比方说，它用一把锁守护自己的状态），而编译器就相信你的话。把它当作最后的手段：本章的全部意义在于让编译器来做检查，而不是把它关掉。\n\n[上一页](@previous)  |  第 8 / 11 页  |  [下一页: Sendable 闭包](@next)";
