Struct还是Class?Swift开发者的永恒问题
每个开始用Swift编程的人迟早都会遇到这个问题。乍一看,这两种结构都可以创建包含数据和方法的对象。但为什么在Stack Overflow上这个问题获得了数千次浏览,而经验丰富的开发者却越来越倾向于选择结构体呢?
答案很简单:因为在struct和class之间的选择直接影响您应用程序的性能、线程安全性和架构。在本文中,我们不仅会讨论理论,还会分析实际示例和场景,在这些场景中Struct明确优于Class。
如果您正在使用Swift,并且仍然“习惯性地”使用来自Objective-C的类——那么本文就是为您准备的。准备好重新思考您的方法吧。
主要区别:值类型 vs 引用类型
在深入细节之前,让我们回顾一下根本区别:
- Struct 是 值类型。在赋值或传递给函数时,会创建数据的副本。
- Class 是 引用类型。在赋值或传递给函数时,传递的是对内存中同一对象的引用。
看似小事。但正是这个“原子级”的区别衍生出了我们接下来要讨论的所有后果。
示例1:Class的意外行为
class PersonClass { var name: String init(name: String) { self.name = name }}
struct PersonStruct { var name: String}
// 测试类let person1 = PersonClass(name: "安娜")let person2 = person1person2.name = "玛丽亚"
print(person1.name) // 玛丽亚!person1也被改变了print(person2.name) // 玛丽亚发现问题了吗?修改了person2的名字,却不经意间也修改了person1的名字。因为它们是内存中的同一个对象。在小例子中这并不严重,但在实际项目中,这种“副作用修改”可能导致难以追踪的bug。
// 测试结构体var person3 = PersonStruct(name: "安娜")var person4 = person3person4.name = "玛丽亚"
print(person3.name) // 安娜!一切正常print(person4.name) // 玛丽亚结构体的行为是可预测的:每个变量拥有自己独立的数据副本。这既安全又透明。
何时Struct是显而易见的选择?
Apple在其文档中建议默认使用struct。让我们列举一下结构体毫无疑问胜出的具体场景。
1. 应该不可变的数据
如果您处理的是创建后不应更改的模型(例如,服务器请求的结果),那么使用具有常量属性的struct是理想选择。
struct UserProfile { let id: Int let name: String let email: String}
// 创建后即可放心。数据受到保护,不会被意外修改。let profile = UserProfile(id: 1, name: "伊万", email: "ivan@example.com")使用类时,如果属性声明为var,您仍然可能错误地修改name。而使用结构体,编译器会迫使您考虑不变性。
2. 小型、自包含的实体
如果您的模型描述的是简单的东西——坐标、尺寸、颜色、金额——请使用struct。这既合乎逻辑又高效。
struct Point { var x: Double var y: Double}
struct Money { var amount: Double var currency: String}
struct Rectangle { var origin: Point var size: Size}这些类型不需要继承和引用管理。它们只是