100 Days of Swift 学习笔记:Day10 吃透结构体(Struct),从自定义类型到属性与初始化
Day10 聚焦 Swift 中构建自定义数据类型的核心 ——结构体(Struct)。结构体能将相关的变量和函数 “打包” 成一个新类型(比如用 Album 结构体整合专辑的标题、歌手、年份),是组织代码的基础(Swift 中的 String、Int、Array 本质都是结构体)。今天学了结构体的定义、属性(存储属性与计算属性)、方法(含修改自身的 mutating 方法)以及初始化器,整理了实操代码和关键细节,新手朋友跟着练能快速掌握 “自定义类型” 的设计思路~
一、结构体基础:创建自己的数据类型
结构体的核心是 “将多个相关的数据和操作封装成一个新类型”,让代码更具逻辑性和可读性。
1. 定义结构体与使用
// 定义一个 Album 结构体(专辑),包含 3 个存储属性和 1 个方法
struct Album {
// 存储属性:结构体中存储的数据(常量或变量)
let title: String // 专辑标题
let artist: String // 歌手
let year: Int // 发行年份
// 方法:结构体中的函数,可访问结构体的属性
func printSummary() {
print("Title: \(title), Artist: \(artist), Year: \(year)")
}
}
// 创建结构体实例(类似调用函数,参数对应属性)
let lostRiver = Album(title: "Lost River", artist: "SunJiaxing", year: 2002)
// 访问属性和调用方法
print(lostRiver.title) // 输出 Lost River
lostRiver.printSummary() // 输出 Title: Lost River, Artist: SunJiaxing, Year: 2002
- 命名规范:结构体名首字母大写(如
Album),属性和方法名首字母小写(如title、printSummary),这是 Swift 的标准约定(与String、Int等系统类型一致)。 - 初始化器(Initializer):创建结构体实例时,Swift 会自动生成一个 “成员逐一初始化器”,要求为每个属性传入值(如
Album(title:..., artist:..., year:...))。也可以显式调用init方法:Album.init(title:..., artist:..., year:...),效果相同。
2. 修改结构体属性的方法:mutating 关键字
如果结构体的方法需要修改自身的属性,必须在方法前加 mutating 关键字(告诉 Swift 这个方法会改变结构体的状态)。
struct Employee {
let name: String // 姓名(常量,不可改)
var vacationRemaining: Int // 剩余假期(变量,可改)
// 修改属性的方法,必须加 mutating
mutating func takeVacation(days: Int) {
if vacationRemaining >= days {
vacationRemaining -= days // 修改属性
print("休假 \(days) 天,剩余 \(vacationRemaining) 天")
} else {
print("假期不足!")
}
}
}
// 注意:必须用 var 声明结构体实例,才能调用 mutating 方法(let 实例为常量,不可修改)
var archer = Employee(name: "SunJiaxing", vacationRemaining: 14)
archer.takeVacation(days: 5) // 输出 休假 5 天,剩余 9 天
print(archer.vacationRemaining) // 输出 9
- 关键限制:用
let声明的结构体实例是 “常量实例”,其所有属性(即使是var声明的)都不能修改,因此无法调用mutating方法(编译时会报错)。
二、结构体的属性:存储属性与计算属性
结构体的属性分两种:存储属性(直接存储数据)和计算属性(动态计算值,不直接存储数据)。
1. 存储属性(Stored Properties)
就是我们前面用 let 或 var 定义的属性,直接存储数据(如 Album 的 title、Employee 的 name)。
2. 计算属性(Computed Properties)
不直接存储数据,而是通过计算得到值,语法上用 { get set } 定义(get 是读取逻辑,set 是写入逻辑)。
struct Employeee {
let name: String // 存储属性:姓名
var vacationAllocated = 14 // 存储属性:总假期天数
var vacationTaken = 0 // 存储属性:已休假期
// 计算属性:剩余假期 = 总假期 - 已休假期
var vacationRemaining: Int {
get { // 读取时的逻辑
vacationAllocated - vacationTaken
}
set { // 写入时的逻辑(newValue 是系统自动提供的参数,代表新值)
// 当设置剩余假期时,反向计算总假期(假设已休假期不变)
vacationAllocated = vacationTaken + newValue
}
}
}
// 使用计算属性
var aarcher = Employeee(name: "Sun Jiaxing")
aarcher.vacationTaken += 4 // 已休 4 天
print(aarcher.vacationRemaining) // 读取:14 - 4 = 10
aarcher.vacationRemaining = 5 // 写入:希望剩余 5 天
// 触发 set 逻辑:vacationAllocated = 4(已休) + 5(新剩余) = 9
print(aarcher.vacationAllocated) // 输出 9(总假期被更新为 9)
- 特点:计算属性更像 “伪装成属性的函数”,每次访问都会重新计算,适合依赖其他属性动态变化的值。
- 简化写法:如果只有
get逻辑(只读计算属性),可以省略get关键字:var vacationRemaining: Int { vacationAllocated - vacationTaken // 只读,省略 get }
三、自定义初始化器:控制结构体的创建过程
初始化器(Initializer)是结构体创建实例时的 “构造函数”,负责为所有属性赋值。Swift 会自动生成默认初始化器,但我们也可以自定义,以满足特殊需求(如自动生成部分属性的值)。
1. 默认初始化器(成员逐一初始化器)
结构体未定义自定义初始化器时,Swift 会自动生成一个初始化器,要求为每个属性传入值:
struct Player {
let name: String
let number: Int
}
// 使用默认初始化器
let player1 = Player(name: "Megan R", number: 15)
2. 自定义初始化器
可以手动定义初始化器,灵活控制实例的创建(比如部分属性自动生成),但必须保证所有属性在初始化器结束时都有值。
struct PlayerCustom {
let name: String
let number: Int
// 自定义初始化器:只需要传入姓名,号码自动生成 1-99 的随机数
init(name: String) {
self.name = name // self 代表当前实例,区分参数名和属性名
number = Int.random(in: 1...99) // 自动生成号码
}
}
// 使用自定义初始化器
let player2 = PlayerCustom(name: "SunJiaxing")
print(player2.name) // 输出 SunJiaxing
print(player2.number) // 输出 1-99 的随机数(如 23)
- 关键语法:
- 初始化器没有
func关键字,名称固定为init; - 用
self.属性名区分参数和属性(当参数名与属性名相同时); - 必须为所有属性赋值(包括常量属性),否则编译报错。
- 初始化器没有
3. 注意事项:自定义初始化器会覆盖默认初始化器
一旦定义了自定义初始化器,Swift 就不会再生成默认的 “成员逐一初始化器”,除非显式实现:
struct PlayerBothInits {
let name: String
let number: Int
// 自定义初始化器1:自动生成号码
init(name: String) {
self.name = name
number = Int.random(in: 1...99)
}
// 显式实现默认初始化器(成员逐一初始化)
init(name: String, number: Int) {
self.name = name
self.number = number
}
}
// 两种初始化器都可以用
let player3 = PlayerBothInits(name: "Anna") // 用自定义初始化器
let player4 = PlayerBothInits(name: "Bob", number: 9) // 用显式默认初始化器
四、Day10 总结:结构体的核心知识点
| 概念 | 作用 | 关键细节 |
|---|---|---|
| 结构体定义 | 将相关属性和方法封装成新类型 | 名首字母大写,属性 / 方法首字母小写 |
| 存储属性 | 直接存储数据 | 用 let(不可改)或 var(可改)定义 |
| 计算属性 | 动态计算值,不直接存储 | 用 get(读取)和 set(写入)定义,newValue 代表新值 |
mutating 方法 |
修改结构体自身属性的方法 | 必须加 mutating 关键字,只能被 var 实例调用 |
| 初始化器 | 创建实例时为属性赋值 | 自定义初始化器必须保证所有属性有值,会覆盖默认初始化器 |
明日计划
Day11 要学 Swift 的 “类(Class)”—— 与结构体类似,但支持继承(这是面向对象编程的核心)。类和结构体在 Swift 中都很重要,尤其是在 SwiftUI 中,视图多用结构体,而数据模型可能用类。有一起打卡的朋友吗?评论区可以分享你设计的结构体(比如 Book、Student 结构体,包含哪些属性和方法)~
更多推荐

所有评论(0)