非Sendable类C1用于Task<Success, Failure>为何可正常运行?
为什么非final类C1能被用作Task的Success类型?
先看你提供的代码片段:
class C1 { var i: Int init(i: Int) { self.i = i } } let t4 = Task<C1, Error>(operation: { return C1(i: 1) }) let v4: C1 = try await t4.value
结合Task的泛型约束Success : Sendable,以及Sendable对类的要求(需为final、存储属性不可变且符合Sendable等),C1明明不满足条件却能正常编译运行,核心原因在于Xcode的默认编译设置未开启严格并发检查。
编译设置的影响
在Xcode 14.1中,Strict Concurrency Checking(严格并发检查)的默认值为Minimal:
- 该模式下,编译器仅对显式标注为
Sendable的类型做基础验证,不会强制校验所有需要符合Sendable的场景(比如Task泛型参数的约束); - 若将此设置修改为
Targeted或Complete,编译器会立即触发错误,明确提示C1不符合Sendable协议要求。
关于Sendable合规性的补充
虽然文档明确了类自动符合Sendable的条件,但还有两种手动声明方式(不推荐随意使用,会引入并发安全风险):
- 直接添加协议声明:
extension C1: Sendable {},编译器会跳过自动检查,依赖开发者自行保证类型的并发安全; - 使用
@unchecked Sendable:extension C1: @unchecked Sendable {},明确告知编译器开发者已确认类型的并发安全性,完全绕过编译器检查。
你的代码并未使用这两种方式,本质是宽松的编译设置让代码“逃过”了检查,但这种写法存在隐患——C1的可变属性i可能在多任务环境下被同时修改,引发数据竞争问题。
内容的提问来源于stack exchange,提问作者Rainer Schwarze
相关产品推荐
相关产品推荐

