Swift 5.9 新特性:不可拷贝的结构体和枚举

前言

在 Swift 中,现存的所有类型都是可拷贝的。也就是说,任何类型的数据都可以创建多份值相同的数据。比如下面的代码:

csharp 复制代码
struct User {
    var name: String
}

var u1 = User(name: "jack")
var u2 = u1 

代码中定义了一个 User 的结构体,接着创建了一个 name 值为 jack 的变量 u1。最后将 u1 的值拷贝给 u2。

在大多数情况下,这种可拷贝是没有问题的,并且这种设计可以避免数据错乱,修改 u2 的值并不会影响 u1,因为它俩数据是分别独立的。

但是当数据资源是唯一的时候,结构体和枚举的这种可复制的设计就不是很好了。与之对应的,类则是可以表示唯一的资源,因为对象在初始化后具有唯一标识,并且只复制对该唯一对象的引用。但是,由于对对象的引用仍然是可复制的,类总是要求共享资源的所有权。并且类的堆分配和引用计数机制也增加了系统的开销,共享访问也会是类的 API 更加复杂或带来额外的消耗。

在这种背景下,Swift 5.9 新推出了不可拷贝的结构体和枚举这项特性,通过 ~Copuable 来实现。

不可拷贝的结构体和枚举

当我们定义的结构体和枚举声明为不可拷贝时,这就意味着它们的值永远只有唯一一份所属权,且其永远无法被拷贝。因为不可拷贝的结构体和枚举的值是有唯一标识的,所以它们会跟类一样有析构函数:deinit。析构函数会在唯一实例的生命周期结束后自动调用。

如果我们想让上面的 User 不可拷贝,可以用下面的代码:

css 复制代码
struct User: ~Copyable {
    var name: String
}

创建 User 实例后,其不可复制的性质意味着它的使用方式与以前版本的 Swift 是有很大区别的。例如,下面的代码看起来可能没什么特别的:

scss 复制代码
func createUser() {
    let newUser = User(name: "Anonymous")

    var userCopy = newUser
    print(userCopy.name)
}

createUser()

但是我们已经将 User 结构体声明为不可复制的,那它是如何获取 newUser 的副本呢?答案是它不能。

将 newUser 分配给 userCopy 会导致原始的 newUser 值被消耗,也就是说 newUser 是不能再被使用,因为所有权现在属于 userCopy。如果你尝试将print(userCopy.name) 更改为 print(newUser.name),你会看到 Swift 编译器会抛出一个编译错误,因为这是不被允许的。

Tips:当结构体被声明为不可拷贝的时候,它仅能遵守 Sendable 协议,遵守别的协议编译器会报错。

相关推荐
人月神话-Lee18 小时前
WWDC26 深度解析:如何在 iOS 27 中打造“秒开”的相机体验
ios·swift·相机·wwdc·用户体验
Tr2e1 天前
🐱 从 0 到 1:用 Swift 手搓一个 macOS 桌面宠物(附源码)
macos·ios·swift
人月神话-Lee2 天前
【WWDC】Core AI:iOS 端侧大模型新纪元
人工智能·ios·ai·swift·wwdc·core ai
2501_916007472 天前
iOS 开发工具选择指南 从编辑器、编译器到自动化构建
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
Fatbobman(东坡肘子)2 天前
WWDC 2026 初印象:符合预期,但更务实 -- 肘子的 Swift 周报 #139
人工智能·macos·ios·swiftui·swift·wwdc
大熊猫侯佩2 天前
WWDC26 全网首发:SwiftUI 8 “可重排序“操作符深度解析
ios·swiftui·swift
人月神话-Lee3 天前
【图像处理】颜色空间——RGB之外的世界
图像处理·人工智能·ios·ai编程·swift·rgb·颜色空间
东坡肘子3 天前
WWDC 2026 初印象:符合预期,但更务实 -- 肘子的 Swift 周报 #139
人工智能·swiftui·swift
大熊猫侯佩3 天前
WWDC26 前瞻:苹果可能放出的“王炸”,不只是 Siri
xcode·swift·wwdc