struct 是 Swift 语言中的一种值类型(value type),其实例在代码片段之间传递时会被复制。与类不同,结构体不支持继承,但可以实现协议、包含属性和方法,并在没有 ARC 的情况下提供可预测的内存管理。根据 Swift 编程语言指南 2026,struct 是 Swift 的基本构建块——甚至标准类型 Int、String、Array 和 Dictionary 也是作为结构体实现的。该语言推荐结构体作为数据建模的首选。
要点
Struct(结构体)是 Swift 中的一种复合数据类型,它将相关的属性和方法分组到一个实体中。与类不同,结构体是值类型(value types):当传递给函数或赋值给新变量时,会创建结构体的独立副本,而不是对原始对象的引用。
Swift 对所有原始类型使用结构体:Int、Double、String、Bool、Array、Dictionary 和 Set。这意味着即使是基本的 Int 数字也像结构体一样行为——赋值时会创建副本。开发人员可以定义自己的结构体,具有任意属性和方法集合。
根据 Swift Evolution (SE-0143),将标准类型实现为结构体的决定是出于性能和可预测性的考虑。值类型不会创建引用循环,不需要 ARC 引用计数,并保证副本的更改不会影响原始数据——这对于多线程场景中的数据不可变性至关重要。
值类型语义(Value type semantics)—— struct 和 class 之间的关键区别。当您将结构体赋值给新变量或传递给函数时,Swift 会创建所有数据的独立副本。副本中的任何更改都不会影响原始数据,从而消除了引用类型特有的副作用。
// 值类型语义示例
struct Point {
var x: Double
var y: Double
}
var p1 = Point(x: 10, y: 20)
var p2 = p1 // p2 是 p1 的独立副本
p2.x = 99 // 只有 p2 改变
print(p1.x) // 10 — p1 不变
print(p2.x) // 99
Swift 使用 Copy-on-Write(COW)来优化复制。如果多个变量引用同一个结构体,但没有一个修改数据,则不会发生实际复制。Swift 在变量之间共享内存,直到第一次修改——然后创建真正的副本。这可以防止不必要的分配操作并加快与集合的工作速度。
默认情况下,结构体的方法不能修改其属性——Swift 要求对进行更改的方法显式指定 mutating。此限制可防止意外修改并使代码可预测:如果方法未标记为 mutating,则保证不会修改结构体。
当您在方法前添加 mutating 关键字时,Swift 可以编写新值到结构体的属性中。实际上,该方法甚至可以通过 self = 完全替换结构体实例为新实例。此机制用于例如 Option 和 Result 类型。
// 带有 mutating 方法的结构体
struct Counter {
private var value: Int = 0
// Mutating 方法——可以修改属性
mutating func increment() {
value += 1
}
// Mutating 方法可以完全替换 self
mutating func reset() {
self = Counter()
}
// Non-mutating 方法——只读
func currentValue() -> Int {
return value
}
}
var counter = Counter()
counter.increment()
print(counter.currentValue()) // 1
counter.reset()
print(counter.currentValue()) // 0
Mutating 规则:结构体必须通过 var 声明,而不是 let —— 常量结构体不能调用 mutating 方法。编译器在构建阶段检查这一点:尝试在 let 常量上调用 mutating 方法会导致编译错误。
在 struct 和 class 之间选择是 Swift 中的基本决策之一。两种类型都可以包含属性、方法、初始化器并实现协议,但在内存语义、继承和生命周期管理方面存在根本差异。
| 特性 | struct | class |
|---|---|---|
| 类型 | 值类型(被复制) | 引用类型(引用) |
| 继承 | 不支持 | 支持 |
| ARC / 引用计数 | 不需要 | 需要 ARC |
| 反初始化 | 不支持 | 支持 deinit |
| 常量中修改属性 | 仅通过 var | 可以通过 let(引用是常量) |
| 类型转换 | 不支持 | 支持 |
| 在集合中存储 | 直接存储(值) | 作为引用存储(指针) |
当数据不需要继承、不应具有共享标识(例如坐标、尺寸、配置)并在模块之间传递时,首选结构体。类用于 UI 组件(UIView、UIViewController)、单例和具有共享标识的对象。
Apple 建议在 Swift 中使用 struct 作为数据建模的默认类型。由于可预测的复制语义和没有引用计数的开销,结构体适用于大多数场景。让我们看看结构体是最佳选择的典型情况。
如果实体包含数据而不需要继承(Product、User、Order、Point),请使用 struct。编译器会自动生成 memberwise 初始化器——您无需手动编写 init。Equatable 和 Hashable 也自动为所有属性满足这些协议的结构体实现。
对于创建后不更改的配置、设置和标志,struct 比 class 更可取。常量(let)结构体保证所有嵌套字段的不可变性——在 class 中,这仅适用于引用,而不适用于对象的内容。
由于值类型语义,结构体在多线程环境中是安全的。每个线程获得独立的数据副本,不会影响其他线程。值类型之间不可能出现竞态条件,这使得结构体成为 SwiftUI 中模型的首选(ObservableObject 需要 class,但 @State 使用 struct)。
// 结构体用于数据模型的示例
struct User: Codable, Identifiable {
let id: UUID
var name: String
var email: String
var isPremium: Bool
// 计算属性——non-mutating
var displayName: String {
isPremium ? "\(name) ⭐️" : name
}
}
// 自动 memberwise 初始化器
let user = User(
id: UUID(),
name: "Alice",
email: "alice@example.com",
isPremium: true
)
// 复制对多线程安全
var userCopy = user
userCopy.isPremium = false
// user.isPremium 保持为 true
当您需要继承(UIKit/AppKit 组件)、共享标识(delegate、observer)或受控对象生命周期(deinit)时,请使用 class。其他所有情况——struct。
常见问题
Struct 在 Swift 中是一种值类型(value type),在代码片段之间传递时被复制。结构体可以包含属性、方法、初始化器并实现协议。Swift 的基本类型(Int、String、Array)都是作为结构体实现的。
Struct — 值类型(赋值时被复制),不支持继承,不需要 ARC。Class — 引用类型(通过引用传递),支持继承、反初始化和引用计数。开发人员推荐 struct 作为默认类型。
Mutating — 指示结构体方法可以修改其属性的关键字。没有 mutating,编译器禁止修改字段。Mutating 方法只能在通过 var 声明的变量上调用,而不是 let。
Copy-on-Write(COW)—— Swift 对结构体的优化,实际数据复制被延迟到第一次修改的时刻。只要所有变量只读取结构体,它们共享一个内存区域。这提高了处理大型集合时的性能。
对无需继承的数据模型、配置、DTO 和多线程场景使用 struct。对 UIKit/AppKit UI 组件、单例、具有共享标识的实体(delegate、observer)和需要反初始化的对象使用 class。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。