目录
Struct 结构体
建立 Struct
与类(Class
)类似
struct Person {
var name: String
var age: Int
func greet() {
print("Hello, my name is \(name) and I am \(age) years old.")
}
}
let person = Person(name: "Alice", age: 25)
person.greet()
// 输出: Hello, my name is Alice and I am 25 years old.
结构体与类的比较
**Struct**
(结构体) 是一种 值类型,用来封装相关的数据和功能。与类(Class
)类似,结构体可以定义属性、方法和初始化器,但它与类最大的不同在于它是 值类型,而Class
类是 引用类型。
特性 | Struct (结构体) | Class (类) |
类型 | 值类型 | 引用类型 |
内存管理 | 不使用引用计数 | 使用引用计数(ARC) |
拷贝行为 | 赋值或传递时会被复制 | 赋值或传递时共享同一个实例 |
继承 | 不支持 | 支持 |
可变性 | let 定义的实例不可变,属性也不可变 | let 定义的实例,属性仍可变 |
值类型的特点
- 拷贝行为:当你将一个结构体赋值给另一个变量或常量时,会创建它的副本,而不是共享相同的实例。
- 独立性:更改一个副本不会影响原始实例,反之亦然。
struct Point {
var x: Int
var y: Int
}
var point1 = Point(x: 1, y: 2)
var point2 = point1 // 创建一个副本
point2.x = 10
print(point1.x) // 输出: 1(原始值未改变)
print(point2.x) // 输出: 10
func
& mutating
struct Point {
var x: Int
var y: Int
// 自定义初始化器
init(_ x: Int, y: Int) {
self.x = x
self.y = y
}
// 析构器用于在实例被销毁之前执行清理工作
deinit {
print("\(x) is being deinitialized.")
}
// 实例方法:打印 x 和 y 的值
func log() {
print("x: \(x), y: \(y)")
}
// 在方法中,属性是不可变的,除非方法被标记为 mutating。
mutating func move(dx: Int, dy: Int) {
x += dx
y += dy
}
}
var point = Point(x: 1, y: 2)
point.log() // 输出: x: 1, y: 2
point.move(dx: 3, dy: 4) // 移动点
point.log() // 输出: x: 4, y: 6
static
static
属性和方法属于类型(Point
),而不是实例。
struct Point {
// static let zero 定义了一个静态常量 zero,它属于 Point 类型,不是任何 Point 实例的。
static let zero: Int = 0
var x: Int
var y: Int
// static 方法,属于类型,不能访问实例属性 x 和 y
// 静态方法,可以直接通过类型名 Point.square 调用
static func square(_ number: Int) -> Int {
print(zero) // 正确,static 方法可以访问 static 属性
// 在 static 方法中,self 指代的是类型,而不是实例。
print(self.zero) // 使用 self 访问静态属性
return number * number
}
}
print(Point.zero) // 调用 static 属性,输出: 0
let result = Point.square(2) // 调用 static 方法
print(result) // 输出: 4
init
& deinit
结构体没有 deinit
,因为它不需要处理复杂的内存管理逻辑(如强引用循环)。
结构体是值类型,不通过引用计数管理生命周期。当结构体超出作用域时,Swift 会直接释放其内存,而无需像引用类型(类)那样调用析构器来手动清理资源。
class Point {
var x: Int
var y: Int
init(_ x: Int, y: Int) {
self.x = x
self.y = y
}
deinit {
print("Point (\(x), \(y)) is being deinitialized.")
}
}
// 测试类的析构器
var point: Point? = Point(1, y: 2)
point = nil // 输出: Point (1, 2) is being deinitialized.
**private**
访问控制
**private(set)**
和 **get**
是属性访问控制的一部分,它们用来控制属性的访问权限,尤其是在类、结构体或枚举中。你可以指定属性的 **getter**
和 **setter**
方法的访问级别,以实现更细粒度的控制。
struct Person {
private var age = 0 // 私有属性,外部不可以读和写
private init() {} // 不需要 init 可以 private 掉
}
使用 private(set)
来保护类的某个属性不被外部直接修改,但允许外部读取该属性的值。
class Counter {
private(set) var count = 0 // count 的 getter 是公开的,setter 是私有的
func increment() {
count += 1 // 可以在类内部修改
}
func reset() {
count = 0 // 可以在类内部修改
}
}
let counter = Counter()
print(counter.count) // 输出: 0,外部可以读取值
counter.increment()
print(counter.count) // 输出: 1,外部可以读取值
// counter.count = 10 // 错误:无法访问 setter,不能修改 count 的值
遵循 protocol 协议
protocol Greetable {
var name: String { get } // 属性要求
func greet() // 方法要求
}
struct Person: Greetable {
var name: String // 属性实现
func greet() { // 方法实现
print("Hello, my name is \(name).")
}
}
let person = Person(name: "Alice")
person.greet()
// 输出: Hello, my name is Alice.
print(person is Greetable) // 输出: true
计算属性
struct Rectangle {
var width: Double
var height: Double
// 计算属性:计算矩形的面积
var area: Double {
return width * height
}
// 计算属性:计算矩形的周长
var perimeter: Double {
return 2 * (width + height)
}
}
let rect = Rectangle(width: 10, height: 5)
print("Area: \(rect.area)") // 输出: Area: 50.0
print("Perimeter: \(rect.perimeter)") // 输出: Perimeter: 30.0
setter
struct Circle {
var radius: Double
// 计算属性:计算圆的面积
var area: Double {
get {
return 3.14159 * radius * radius
}
set {
radius = sqrt(newValue / 3.14159) // 使用传入的新值来更新 radius
}
}
}
var circle = Circle(radius: 5)
print("Initial Area: \(circle.area)") // 输出: Initial Area: 78.53975
// 使用 setter 设置新值来改变 radius
circle.area = 50
print("New Radius: \(circle.radius)") // 输出: New Radius: 3.989422804014327
print("New Area: \(circle.area)") // 输出: New Area: 50.0
只读
struct Person {
var firstName: String
var lastName: String
// 只读计算属性:返回全名
var fullName: String {
return "\(firstName) \(lastName)"
}
}
let person = Person(firstName: "John", lastName: "Doe")
print(person.fullName) // 输出: John Doe
属性观察器
可以在计算属性中使用 **willSet**
和 **didSet**
来观察和响应属性值的变化,但对于计算属性本身,通常只会使用 **didSet**
来观察它们所依赖的其他属性变化。
struct Rectangle {
var width: Double {
willSet {
print("Width will be set to \(newValue)")
}
didSet {
print("Width changed from \(oldValue) to \(width)")
}
}
var height: Double {
willSet {
print("Height will be set to \(newValue)")
}
didSet {
print("Height changed from \(oldValue) to \(height)")
}
}
// 计算属性:计算矩形的面积
var area: Double {
return width * height
}
}
var rect = Rectangle(width: 10, height: 5)
rect.width = 20 // 输出: Width will be set to 20
// 输出: Width changed from 10.0 to 20.0
rect.height = 10 // 输出: Height will be set to 10
// 输出: Height changed from 5.0 to 10.0
print("Area: \(rect.area)") // 输出: Area: 200.0
lazy
class MyClass {
var firstName: String
var lastName: String
// 计算属性,实时反映最新的值
var fullName3: String { "\(firstName) \(lastName)" }
// 计算属性 首次捕获计算
lazy var fullName2: String = "\(firstName) \(lastName)"
// 闭包 首次捕获计算
lazy var fullName: String = {
print("get fullName ..")
return "\(firstName) \(lastName)"
}()
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
let person = MyClass(firstName: "John", lastName: "Doe")
print("lazy ..") // 输出: lazy ..
print(person.fullName) // 输出: get fullName ..
// 输出: John Doe
print(person.fullName) // 输出: John Doe
print(person.fullName2) // 输出: John Doe
print(person.fullName3) // 输出: John Doe
person.firstName = "Jane"
print(person.fullName) // 输出: John Doe
print(person.fullName2) // 输出: John Doe
print(person.fullName3) // 输出: Jane Doe
简单的 lazy
属性
class DataFetcher {
lazy var data: String = {
// 模拟一些计算或数据加载
print("Data is being loaded...")
return "Fetched Data"
}()
func fetchData() -> String {
return data
}
}
let fetcher = DataFetcher()
print("Before accessing data.")
print(fetcher.fetchData()) // 第一次访问时加载数据
print(fetcher.fetchData()) // 后续访问直接返回已经加载的数据
计算闭包
class Database {
lazy var connection: String = {
// 模拟建立数据库连接的操作
print("Connecting to the database...")
return "Database Connection Established"
}()
}
let db = Database()
print("Before connecting to database.")
print(db.connection) // 第一次访问时建立
Property Wrapper 装饰器
@propertyWrapper
struct Uppercase {
private var value: String
init(wrappedValue: String) {
self.value = wrappedValue
}
var wrappedValue: String {
get { return value }
set { value = newValue.uppercased() }
}
}
struct Person {
@Uppercase var name: String
}
var person = Person(name: "john doe")
print(person.name) // 输出: john doe
person.name = "jane doe"
print(person.name) // 输出: JANE DOE