Swift Struct
有了当前的 o1 或者 claude 等工具,学东西总结的时候就方便多了,不用再去翻书,直接在这里写就好了。还能一步一步当老师来教你,这样的感觉真好。
一句话总结
**struct
和 class
struct
是值类型,适合简单数据模型,复制后彼此独立,存在栈上。class
是引用类型,适合共享状态或继承,多个引用共享同一个对象,存在堆上。
struct 里定义的属性是引用类型的话,struct 还是值类型吗?
- struct 的"值类型"体现在它的复制行为 - 当 c1 赋值给 c2 时,创建了一个新的 struct 实例
- 新的 struct 实例会复制所有存储属性,但对于引用类型的属性,复制的是引用(指针)而不是底层数据
struct 对比 class
下面是一份简明、通俗易懂的对比,帮助你理解在 Swift 中使用 struct
和 class
建立 Model 有何区别,以及各自适用场景:
1. 值类型 vs. 引用类型
struct
(值类型):当你复制一个 struct(比如赋值给另一个变量、或作为函数参数传递)时,会得到它的独立副本,后续对副本的更改不会影响原对象。class
(引用类型):当你复制一个 class 实例时,其实只是多了一个“指针”,所有引用都指向同一个对象。对其中一个副本做修改,别的副本也会跟着变化。
举例:
struct PersonStruct {
var name: String
}
class PersonClass {
var name: String
init(name: String) {
self.name = name
}
}
var s1 = PersonStruct(name: "Alice")
var s2 = s1
s2.name = "Bob"
print(s1.name) // "Alice"(原来的 struct 不变)
var c1 = PersonClass(name: "Alice")
var c2 = c1
c2.name = "Bob"
print(c1.name) // "Bob"(class 共享同一个对象)
2. 继承 vs. 组合
struct
:不能继承其他 struct,也不能被继承;更鼓励用“组合”来构建复杂对象。class
:可以继承父类,也支持多态等特性;在某些场景(如必须使用 UIKit/AppKit 的继承机制)时是必须的。
3. 适用场景
-
数据载体 / 轻量模型:
- 如果你只是想存储数据,且希望在复制时互不干扰,通常用
struct
更简单,也符合 Swift“提倡使用值类型”的思路。 - 适合存放一些属性,如
title
、content
、date
等。
- 如果你只是想存储数据,且希望在复制时互不干扰,通常用
-
需要共享可变状态或继承:
- 如果你想让多个地方共享同一个实例,并且其中一个地方改了对象后,其他地方立刻跟着变,则用
class
。 - 需要继承或 KVO(Key-Value Observing)等特性时,也需要用
class
。
- 如果你想让多个地方共享同一个实例,并且其中一个地方改了对象后,其他地方立刻跟着变,则用
4. 性能及内存
- 一般来说,struct 较简单,系统能做很多优化,比如在栈上分配。
- class 通常会在堆上分配,需要引用计数(ARC)来管理内存。
- 在绝大多数应用场景下,两者性能差距不大,可读性和语义才是更重要的选择依据。
5. 何时用 struct、何时用 class
- 优先用
struct
:小而简单、属性类型都是值语义、想要复制后相互独立,或仅仅作数据传递。 - 考虑用
class
:需要继承层次或需要共享同一个实例(例如管理器、缓存对象、需要被观察等)。
总结
struct
在 Swift 中是值类型,复制后彼此独立,适合做纯数据模型。class
是引用类型,多个引用共享同一个对象,适合需要共享状态或继承的场景。- Swift 更推崇在可能的情况下用
struct
表达数据,只有在需要继承或引用语义时才使用class
。
struct 里定义的属性是引用类型的话,struct 还是值类型吗?
这是个非常好的问题,让我深入分析一下:
当我们说"struct 是值类型"时,实际上指的是 struct 实例的复制行为,而不是其内部数据的完整复制。让我用代码来说明:
class DataClass {
var value: Int
init(value: Int) { self.value = value }
}
struct Container {
var classData: DataClass // 引用类型
var normalValue: Int // 值类型
}
// 测试复制行为
let data = DataClass(value: 10)
var c1 = Container(classData: data, normalValue: 5)
var c2 = c1 // 复制行为发生时
print(c1.classData === c2.classData) // true - 同一个引用
这里的关键点是:
- struct 的"值类型"体现在它的复制行为 - 当 c1 赋值给 c2 时,创建了一个新的 struct 实例
- 新的 struct 实例会复制所有存储属性,但对于引用类型的属性,复制的是引用(指针)而不是底层数据
- struct 保证了它自身的独立性,但不能改变其内部引用类型属性的引用语义
更准确的说法应该是:
- struct 提供了结构级别的值语义
- 但不能改变其内部引用类型成员的引用语义
这就像是一个包装盒(struct)可以被完整复制,但盒子里的某些东西(引用类型)可能是指向同一个实体的引用。
所以,说"struct 是值类型"是正确的,因为 struct 本身的复制行为确实符合值语义,只是这个值语义不会递归地应用到内部的引用类型属性。