现实世界的数据很少是单个数字——一个学生有姓名、年龄、成绩三种信息。结构体把【不同类型的几样】捆成一包当一张记录卡,枚举把【只有几种可能的取值】逐个命名——自定义类型的两块基石。
3-4~3-8 处理的都是【一种类型】的数据,这一篇开始【造自己的类型】。回收 C++ 课第八章(结构体与共用体)与第十章(类——结构体加方法的后继),数据库课 5-6 的【实体与属性】是同一个思想在数据设计层的投影。
一、结构体:不同类型捆成一包
描述一个学生:姓名是字符串、年龄是整数、平均分是浮点——三种类型,各有用途,拆着传(传三个变量)又散又容易漏。结构体的思路:打包成一个整体:
struct Student { // C 语言的写法
char name[20]; // 字符串(C 的字符数组,见 3-9 的 \0)
int age;
float score;
};
打包之后,一个变量就是【一张完整记录卡】:
# Python 里用 dataclass(现代等价物)
from dataclasses import dataclass
@dataclass
class Student:
name: str
age: int
score: float
stu = Student(name="王明", age=16, score=92.5)
print(stu.name, stu.score) # 王明 92.5 —— 按字段名取
价值:字段有名(不怕传错位)、可以整体传递/存入列表、加字段只改一处。面向对象里的【类】就是结构体的进化——多了方法(行为)。
二、枚举类型:有限取值逐个命名
有些量天生只有几种可能:星期一到日、季节四季、订单状态【待付款/已付款/已发货】。用裸数字记(0=周一、1=周二)就是 3-6 批判过的魔法数字——枚举把它们命名:
from enum import Enum
class Weekday(Enum):
MON = 1
TUE = 2
SUN = 7
today = Weekday.MON
print(today) # Weekday.MON
print(today == Weekday.MON) # True
三重好处:可读(Weekday.MON 比 1 明白)、防错(写成 Weekday.WED 拼错当场报错,写 3 谁也不知道对不对)、取值封闭(只有这几个成员)。
三、两者配合:记录卡+下拉菜单
实际项目里常组合:学生结构体里的【性别】【年级】字段,用枚举当类型——结构体管【有哪几项】,枚举管【某项只能填哪几个】。数据库课 5-19 设计书评网站表时的【确定属性取值】是同一件事的设计期版本。
四、动手 Demo:记录卡装进列表
from dataclasses import dataclass
from enum import Enum
class Level(Enum):
A = "优秀"
B = "良好"
@dataclass
class Student:
name: str
age: int
level: Level
roster = [Student("王明", 16, Level.A), Student("李华", 17, Level.B)]
for stu in roster:
print(stu.name, stu.level.value)
看到什么算成功:
王明 优秀
李华 良好
读结果:结构体当元素装进列表(3-8 的走廊里住起了【记录卡】),枚举用 .value 取出人类可读的字面值——两个自定义类型合体,数据立刻有模有样。
五、30 秒实验
跑 Student("王明", 16, 99)——dataclass 不拦类型不匹配(99 不是 Level),但打印 stu.level 会露馅。换成 C 的 enum 或 Java 的 enum 编译器就会拦。枚举的防错力取决于语言的检查强度——30 秒看清这一点。
六、常见误区
- 【结构体和类是两种完全不同的东西】——错。C++ 里
struct和class只差默认访问权限;结构体是【只有数据的类】,类是【加了行为的结构体】。 - 【枚举就是给数字起别名,用常量代替也行】——不完整。枚举是封闭集合:类型系统保证取值不越界、能穷举、能配合 switch/match;散装常量没有这些保护。
- 【数据都该用结构体打包】——过犹不及。单个数值、简单的键值对(3-13 的字典)硬包成结构体反而啰嗦;字段的种类和关系变复杂了,才是打包的时机。
自测三问(点开对答案)
1. **结构体解决什么问题?** 答:把【不同类型的若干相关数据】捆成一个整体——字段有名、可整体传递、加字段只改定义一处。 2. **枚举比【散装常量】强在哪?** 答:封闭取值+类型检查——只可能取定义过的成员,拼错或越界当场暴露;可读性也从【数字 3】升级为【命名成员】。 3. **类和结构体的关系?** 答:类=结构体+方法(行为);C 的 struct 只有数据,C++/Java/Python 的 class 让【数据】和【操作数据的函数】住到一起。- ☐ 下一节(3-12 类型转换、自动类型转换、强制类型转换、溢出)
相关笔记
- 数组 —— 结构体常装进列表当元素
- C++ 8.1 · 结构体 —— C 语言的原始形态
- 数据库 5-6 · 思考数据之间的关系 —— 实体与属性的另一投影
- ⌨️ 编程原理 · 索引 —— 全课路线图