5月27日 11:29

Swift 结构体和类有什么区别?什么时候用 struct?

结构体(struct)和类(class)的核心区别:struct 是值类型,赋值拷贝;class 是引用类型,赋值传引用。Swift 推荐优先用 struct——更安全(不受其他代码影响)、更简单(没有循环引用)、更高效(栈分配 + 写时复制)。

class 能做而 struct 做不了的事:继承、类型转换(is/as)、析构器(deinit)、引用计数(ARC)、共享同一实例。反过来,struct 能做而 class 做不了的事:编译器自动合成 init(class 没有成员初始化器)、不需要手动管理内存、天然线程安全(值隔离)。

追问

什么时候必须用 class?

三种情况:需要继承(UIKit 的视图体系)、需要共享状态(单例、ViewModel 在多个视图间共享)、需要 deinit 清理资源(关闭文件、取消网络请求)。除了这三种,用 struct。

struct 的方法为什么默认不能修改属性?

struct 是值类型,方法调用时 self 是 let(不可变)。要修改属性必须标记 mutating,这会让编译器在调用时确保变量是 var 而不是 let。class 不需要 mutating——引用类型的方法调用不影响 self 的可变性。mutating 的另一个效果:在 mutating 方法里可以给 self 赋新值,比如 self = Self()

struct 可以实现协议吗?和 class 实现协议有什么区别?

都可以实现协议。区别在于:如果协议要求 mutating 方法,struct 实现时必须标 mutating,class 不需要——因为 class 的方法天然可以修改属性。另外,class 实现的协议可以用作 existencial(let x: Protocol = MyClass()),struct 实现的协议在 Swift 5.7 之前有更多限制(有关联类型时不能直接当类型用)。

struct 的 init 是怎么合成的?

如果没有自定义 init,编译器自动合成成员初始化器:Point(x: 1, y: 2)。一旦你写了自定义 init,成员初始化器就没了。class 没有自动合成的成员初始化器——必须手写 init,或者所有属性都有默认值且不需要传参。Swift 5.10 之后 struct 在有自定义 init 的同时可以保留成员初始化器,用 init(x:y:) 即可。

为什么 Apple 在 SwiftUI 里大量用 struct?

两个原因:值语义让视图状态隔离——修改一个视图的状态不会意外影响其他视图;struct 没有引用计数开销,视图创建销毁频繁,用 struct 性能更好。SwiftUI 的 View 协议要求是 struct,body 属性每次调用都生成新的值,diff 算法比较新旧值决定是否更新。如果用 class,diff 成本和内存管理都会更复杂。

写段代码

swift
struct Point { var x: Int, y: Int } class Node { var value: Int = 0; var next: Node? } // 值类型:拷贝隔离 var p1 = Point(x: 1, y: 2) var p2 = p1 p2.x = 10 print(p1.x) // 1 // 引用类型:共享实例 var n1 = Node(); n1.value = 42 var n2 = n1; n2.value = 99 print(n1.value) // 99 // mutating 修改属性 struct Counter { var count = 0 mutating func increment() { count += 1 } } var c = Counter() c.increment()
标签:Swift