Swift 中的结构体和类有什么区别?在什么情况下应该选择结构体而不是类?
Swift 中的结构体和类都是用于定义自定义数据类型的构造,但它们在内存管理、赋值行为和使用场景上有重要区别。
主要区别:
-
值类型 vs 引用类型:
- 结构体是值类型,赋值时创建副本
- 类是引用类型,赋值时传递引用
- 示例:
swift
struct Point { var x: Int var y: Int } class Circle { var center: Point var radius: Int init(center: Point, radius: Int) { self.center = center self.radius = radius } } var point1 = Point(x: 0, y: 0) var point2 = point1 point2.x = 10 print(point1.x) // 0 (point1 不受影响) var circle1 = Circle(center: Point(x: 0, y: 0), radius: 5) var circle2 = circle1 circle2.radius = 10 print(circle1.radius) // 10 (circle1 受影响)
-
继承:
- 类支持继承,可以继承其他类的属性和方法
- 结构体不支持继承
- 示例:
swift
class Vehicle { var speed: Int = 0 func accelerate() { speed += 10 } } class Car: Vehicle { var brand: String init(brand: String) { self.brand = brand } }
-
类型转换:
- 类支持类型检查和转换(is、as)
- 结构体不支持类型转换
- 示例:
swift
let vehicle: Vehicle = Car(brand: "Toyota") if let car = vehicle as? Car { print(car.brand) }
-
引用计数:
- 类使用 ARC(自动引用计数)管理内存
- 结构体不需要引用计数,直接在栈上分配
- 类可能导致循环引用,需要使用 weak 或 unowned
-
析构器:
- 类可以定义析构器(deinit)
- 结构体不能定义析构器
- 示例:
swift
class FileHandler { let fileHandle: FileHandle init(path: String) { self.fileHandle = FileHandle(forReadingAtPath: path)! } deinit { fileHandle.closeFile() } }
选择结构体的场景:
- 数据模型主要是值类型
- 数据需要独立存在,不希望被意外修改
- 数据相对较小,复制成本较低
- 不需要继承
- 需要线程安全的操作
- 需要比较值相等性
选择类的场景:
- 需要继承和多态
- 需要共享状态
- 数据较大,复制成本高
- 需要控制生命周期和内存管理
- 需要使用标识符比较
- 需要使用析构器
最佳实践:
- 优先使用结构体,只有在需要引用类型特性时才使用类
- 使用结构体表示简单的数据模型
- 使用类表示具有身份和行为对象
- 在需要继承时使用类
- 注意类可能导致的循环引用问题