值类型与引用类型:struct 与 class 的分工

值类型与引用类型:structclass 的分工

1. 结论(先给答案)

  • struct(及多数 enum)是值语义 :赋值/传参在模型上产生独立副本;class 是引用语义:多个变量可指向同一实例。
  • 默认优先 struct ,除非需要引用身份单继承运行时特性(deinit@objc 等) 、或与 UIKit/ObjC 对象模型 对齐,再选 class
  • class 实例由 ARC 管理生命周期struct 本身 走引用计数,但若 struct 含有 class 或闭包等引用类型字段,被包含的对象仍参与 ARC。
  • Swift 的类不支持 C++ 式多重继承 ;通过 协议多实现 + 协议默认实现 + 组合 达到类似「多能力」表达。

2. 深入浅出

  • 直觉 :改 struct 的副本一般不拖累另一处;改 class 的「一处」可能所有人看见。
  • 机制class 实例在 上分配,变量持有引用struct值语义 传递,实现上可驻留在栈、寄存器、或作为更大对象的一部分语义上始终是拷贝(大值可能经优化,但编程模型不变)。

2.1 structclass 的使用场景(列举)

下列用于选型 checklist ;同一需求可能有多种写法,最终以团队规范 + 性能测量为准。

更适合 struct 的典型场景(尽量列全)

场景 说明
领域值模型 坐标、金额、时间区间、DTO(无「唯一身份」需求)
不可变或 copy-on-write 友好数据 let、函数式风格配合
不需要继承 能力用 协议 + 扩展 组合,而非子类
SwiftUI View Viewstruct,由状态驱动重建
并发下减少共享可变引用 值拷贝缩小别名;仍注意「struct 内引用类型字段」的共享
与值语义强绑定的标准库风格 如自定义小集合、数学向量(无统一「身份」)
C / 固定布局互操作 有时需 struct 与 C 布局对齐(另涉 @frozen 等,进阶)

更适合 class 的典型场景(尽量列全)

场景 说明
需要引用身份 === 判断「是不是同一个对象」;共享生命周期
需要单继承 class Child: Parent仅允许一个父类
需要 deinit 释放非内存资源(句柄、取消观察者等);structdeinit
与 ObjC 互通 继承 NSObject@objcdynamic、KVO 等
UIKit / AppKit 组件 UIViewControllerUIView 等均为 class
共享可变状态且有意共享 如共享缓存、注册表(需配合线程安全策略)
经典单例(需慎用) 全局唯一实例,通常 class + 静态持有

明确不选某一侧的边界

需求 说明
多重继承(多个父类) Swift 不支持;见 §2.3
仅要「多种能力」 多协议 + 协议扩展 ,或 组合(持有一个或多个服务对象)

2.2 引用计数(ARC)与 class

  • ARC(Automatic Reference Counting) 只作用于引用类型堆实例 (主要是 class;另有部分运行时对象如闭包捕获上下文等,细节见进阶资料)。
  • 规则 :每多一个强引用 ,引用计数增加;强引用结束则减;为 0 时释放 对象。weak 不延长生命周期;unowned 假定对象仍存活(不 bump 强引用,误用会野指针)。
  • struct 与 ARCstruct 整体 不按「实例」做 RC;若 struct 的存储属性里有 class 类型闭包 等,这些引用 会参与 ARC。复制 struct复制引用 (若属性是引用类型),从而可能多一个强引用 指向同一个堆对象。
  • 与 OC :OC 的 ARC 规则与 Swift 对 ObjC 对象 一致;纯 Swift class 同样走 ARC。

可核对:Automatic Reference Counting(Swift 官方)。

2.3 继承与「多继承」:Swift 的实际模型

  • 仅单继承 ------class B: A 只能有一个父类 A
  • 协议可多采纳 ------class C: A, P1, P2, P3A 为父类(至多一个),P1... 均为协议;或 struct S: P1, P2
  • 协议组合类型P1 & P2(存在类型),用于「同时满足多个协议」。
  • 默认实现extension Proto { } 提供协议方法默认实现,接近「混入」能力,但不是子类化多重继承。
  • 与 OC 对照 :OC 同样单继承 + 多协议(@protocol + Category ;Swift 用 extension 更接近「非侵入式扩展」,语义与运行时注入与 Category 仍有差异。

结论 :面试或文档中说「Swift 没有多继承」通常指 没有多父类 ;若说「可以多协议」,应明确是 协议多实现 ,避免与 C++ 多重继承混淆。

2.4 内存分布(概念级,非实现承诺)

实现细节随 ABI、优化级别、平台变化;以下用于建立正确心智不要依赖未文档化布局写代码。

对象 常见直觉(教学用) 注意
class 实例 一般在上;头指针含类型信息与引用计数等元数据(具体布局见 Swift ABI) 大小与对齐由编译器决定
struct 常放在寄存器 ,或内联到父 struct/class 的存储中 struct 可能经临时缓冲等方式,仍不改变值语义
enum(无关联值或简单) 常紧凑存储;有关联值时带 payload Optional 等优化相关
闭包 捕获列表可能形成堆上闭包对象,参与 ARC 与「值类型」并列讨论

错误说法 :「struct 永远在栈上」------不准确;正确说法 :「struct值类型 ,按值语义使用;存放位置是实现细节。」

进阶阅读:Swift ABI / MemoryLayout(仅测大小对齐,不覆盖运行时堆块细节)。

3. Objective-C 对照

OC Swift 为何不同
业务对象多为 NSObject 子类(引用) 一等值类型 struct Swift 鼓励不可变与拷贝语义,减少共享可变状态
C struct 与 Swift struct 不等价 Swift struct 可有方法、协议 语言层统一值抽象
单继承 + 协议 + Category 单继承 + 多协议 + extension 无多父类;扩展机制不同

混编 :纯 Swift struct 对 OC 不可见 ;需 OC 侧使用时用 class + @objc 或桥接包装。

4. 为什么这么实现

  • 值类型利于局部推理与并发友好(无共享可变引用时)。
  • 引用类型保留身份===)与单继承(与 UIKit/AppKit、ObjC 模型一致)。
  • 禁止多父类 避免菱形继承等复杂度;能力用协议组合替代。

可核对:Structures and Classes(Swift 官方指南)。

5. 有没有更好的方式

  • 全用 class :与 OC 一致但易共享可变状态;代价:更多循环引用与锁。
  • 全用 struct :无法表达需要身份、单继承、deinit 或 ObjC 子类化;代价:大值拷贝需 profiling。
  • 协议 + 结构体 + 组合服务 :替代深继承树;代价:样板与 DI 设计成本。

6. 案例与反例

  • 正例Examples/SwiftSharing/Sources/FoundationExamples/main.swift --- F01Demo;或 Sources/ValueSemantics/main.swift --- Point / Box。运行:swift run foundation-examplesswift run value-semantics
  • 反例Array 持有多个同一 UIView 引用,改一处影响多处------引用语义 ,非 Array 的锅。
  • 反例 :假设「struct 里没有 class 就不会泄漏」------若 struct 内持有闭包且强捕获 self,仍可能通过闭包间接持有 class,需看引用图。

7. 坑与排雷

把「需要唯一身份」的模型做成 struct(例如需要 === 判同一对象)------应改为 class 或显式 ID。

误以为「值类型 = 无 ARC」------值类型内的引用仍参与 ARC。

8. 延伸阅读与自测

  • Swift Book:Classes vs Structures;ARC 章节;Protocols。
  • 自测:MemoryLayout<Point>.sizeclass 实例大小分别测什么?
  • 自测:为何 Swift 不允许多父类?

9. 面试常见问法

问:structclass 区别?Swift 何时用 struct

  • 要点 :① 值 vs 引用;② 默认 struct;③ 身份 / 继承 / deinit / ObjC / UIKit → class
  • 追问Arrayclass 时拷贝数组会不会拷贝对象?------不会,拷的是引用。
  • 追问 :引用计数作用在谁上?------引用类型实例struct 内嵌引用则嵌套对象参与 RC。
  • 追问 :Swift 有多继承吗?------无多父类可多协议,与协议扩展、组合。
  • 追问struct 一定在栈上吗?------ ,位置是实现细节;值语义才是保证。

符号FoundationExamplesMainF01DemoPointBox --- Sources/FoundationExamples/main.swift;亦可对照 ValueSemantics target。

相关推荐
报错小能手3 天前
ios开发方向——对于实习开发的app(Robopocket)讲解
开发语言·学习·ios·swift
茶底世界之下3 天前
Harbeth:高性能Metal图像处理库,让你的图片处理速度飞起来!
前端·github·swift
风舞雪凌月3 天前
【趣谈】移动系统和桌面系统编程语言思考
java·c语言·c++·python·学习·objective-c·swift
UXbot4 天前
AI App 设计生成工具哪个好?
ui·kotlin·软件构建·产品经理·ai编程·swift
黄林晴4 天前
Swift 杀进 Android,Google 和 Apple 都要失眠了?
android·前端·swift
东坡肘子4 天前
一墙之隔,不同的时空 -- 肘子的 Swift 周报 #129
人工智能·swiftui·swift
harder3215 天前
Swift 面向协议编程的 RMP 模式
开发语言·ios·mvc·swift·策略模式
KevinCyao7 天前
iOS短信营销接口示例代码:Swift/Xcode集成营销短信API的完整开发教程
ios·swift