Dart 枚举:enum 类型
枚举是 Dart 中用于定义一组相关常量的类型。它让代码更清晰、更安全,用enum 关键字定义,编译时就能检查值的合法性。
认识枚举类型
枚举类型把相关的常量组织在一起,形成一个命名的值集合。比如一周的天数、订单的状态、颜色的类型——这些天然的分类场景,都适合用枚举表示。
enum Status {
pending, // 待处理
processing, // 处理中
completed, // 已完成
cancelled // 已取消
}
枚举的核心优势体现在三个方面:类型安全——编译器会检查赋值是否合法,拒绝无效值;语义清晰——代码中看到 Status.completed,含义一目了然;易于维护——新增或修改状态时,只需改动枚举定义,所有使用处自动获得类型检查保护。
基本定义与使用
定义枚举
使用 enum 关键字定义枚举,大括号内列出所有可能的值:
enum LogLevel {
debug, // 调试信息
info, // 普通信息
warning, // 警告
error, // 错误
critical // 严重错误
}
枚举值的命名遵循小驼峰式(lowercase),与类名的大驼峰式区分开来。
声明和使用变量
声明枚举类型的变量时,赋值必须来自枚举定义的集合:
LogLevel currentLevel = LogLevel.info;
// 通过枚举访问成员
LogLevel level = LogLevel.warning;
// 使用点语法获取枚举值
if (currentLevel == LogLevel.error) {
print('发生错误');
}
Dart 的枚举类型是强类型的,不能把普通整数或字符串直接赋给枚举变量,也不能在枚举类型和非枚举类型之间自由转换——这种约束正是类型安全性的来源。
枚举的属性和方法
Dart 为枚举提供了几个实用的预定义属性和方法,熟练使用它们能大幅简化代码。
values 属性
values 返回枚举的所有实例,按定义顺序排列:
// 遍历所有日志级别
for (LogLevel level in LogLevel.values) {
print(level);
}
// 输出: LogLevel.debug, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical
values 属性的典型应用场景包括:生成下拉选项列表、实现"全部"筛选功能、验证用户输入是否在允许范围内。
name 属性
每个枚举实例都有 name 属性,返回其字符串名称:
LogLevel level = LogLevel.warning;
print(level.name); // 输出: warning
// 配合 values 实现名称到枚举的映射
LogLevel parsed = LogLevel.values.firstWhere(
(e) => e.name == 'error',
orElse: () => LogLevel.info
);
index 属性
index 返回枚举值在定义时的位置(从 0 开始):
print(LogLevel.debug.index); // 输出: 0
print(LogLevel.info.index); // 输出: 1
print(LogLevel.warning.index); // 输出: 2
// 利用 index 比较优先级
if (currentLevel.index >= LogLevel.error.index) {
print('需要立即处理');
}
枚举在 switch 中的使用
枚举与 switch 语句是绝配,编译器会检查是否覆盖了所有情况:
String getLevelDescription(LogLevel level) {
switch (level) {
case LogLevel.debug:
return '详细调试信息';
case LogLevel.info:
return '一般信息';
case LogLevel.warning:
return '警告信息';
case LogLevel.error:
return '错误信息';
case LogLevel.critical:
return '严重错误';
}
}
使用 switch 处理枚举时,必须覆盖所有分支——Dart 编译器会强制检查这一点,如果漏掉任何一种情况,编译就会报错。这个特性帮你避免"未处理某个状态"的 bug。
为枚举添加自定义属性和方法
Dart 的枚举实际上是一个特殊的类,可以添加自定义属性和构造函数,赋予枚举更丰富的表达能力。
添加属性和构造函数
为枚举定义属性时,每个枚举值都需要通过构造函数传入对应的值:
enum Priority {
low(1, '低优先级'),
medium(2, '中优先级'),
high(3, '高优先级'),
urgent(4, '紧急');
final int level; // 优先级数值
final String label; // 显示标签
const Priority(this.level, this.label);
// 添加方法
bool isUrgent() => level >= 3;
}
void main() {
Priority p = Priority.high;
print(p.level); // 输出: 3
print(p.label); // 输出: 高优先级
print(p.isUrgent()); // 输出: true
}
注意:枚举的构造函数必须是 const,且所有枚举实例都需要在枚举体内明确定义。
添加命名工厂构造函数
如果需要根据字符串或其他条件创建枚举实例,可以添加工厂构造函数:
enum TemperatureUnit {
celsius('C'),
fahrenheit('F'),
kelvin('K');
final String symbol;
const TemperatureUnit(this.symbol);
// 从符号获取单位
factory TemperatureUnit.fromSymbol(String symbol) {
return values.firstWhere(
(u) => u.symbol == symbol,
orElse: () => throw ArgumentError('不支持的温度单位符号: $symbol')
);
}
}
// 使用
TemperatureUnit unit = TemperatureUnit.fromSymbol('F');
```
---
## 常见应用场景
### 状态管理
订单状态、任务状态、用户权限等级——这些有限状态的场景最适合使用枚举:
```dart
enum OrderStatus {
created, // 已创建
paid, // 已支付
shipped, // 已发货
delivered, // 已送达
cancelled, // 已取消
refunded // 已退款
}
class Order {
final String id;
OrderStatus status;
Order(this.id, this.status);
void updateStatus(OrderStatus newStatus) {
// 业务规则:已取消或已退款不能变更状态
if (status == OrderStatus.cancelled || status == OrderStatus.refunded) {
throw StateError('当前状态不允许变更');
}
status = newStatus;
}
bool get canBeCancelled {
return status == OrderStatus.created ||
status == OrderStatus.paid;
}
}
```
### 配置选项
应用的配置项、API 请求方法、UI 主题模式等固定选项集:
```dart
enum HttpMethod { get, post, put, delete, patch }
enum ThemeMode { light, dark, system }
enum ApiVersion { v1, v2, v3 }
class ApiRequest {
final HttpMethod method;
final ApiVersion version;
final String endpoint;
ApiRequest({
required this.method,
required this.version,
required this.endpoint,
});
String get url {
return 'https://api.example.com/${version.name}/$endpoint';
}
}
```
### 错误类型
定义应用中可能出现的错误类型,便于分类处理:
```dart
enum ValidationError {
emptyField,
invalidEmail,
passwordTooShort,
mismatchedPassword
}
enum AuthError {
invalidCredentials,
accountLocked,
sessionExpired,
permissionDenied
}
```
---
## 使用枚举的注意事项
Dart 枚举存在一些限制,理解这些限制能帮助你更好地设计代码结构。
**枚举不能继承或被继承**——枚举类型是 final 的,每个枚举都是 `Enum` 类的隐式子类,但不能创建继承枚举的子类,也不能让其他类继承枚举。
**不能动态创建枚举实例**——枚举值必须在定义时全部写死,运行时无法添加新的枚举值。
**不能在 switch 中使用 continue 跳转到另一个 case**——Dart 的 switch 语句不允许 case 之间相互跳转。
```dart
// 错误示例:不能在 switch 中使用 continue 跳转
switch (status) {
case OrderStatus.created:
print('创建');
continue paying; // 这在 Dart 中不允许
paying:
case OrderStatus.paid:
print('支付');
break;
}
```
**枚举值的比较**——使用 `==` 操作符比较枚举是安全的,因为每个枚举值都是单例的:
```dart
OrderStatus s1 = OrderStatus.shipped;
OrderStatus s2 = OrderStatus.shipped;
print(s1 == s2); // 始终输出: true
```
---
## 完整示例:限时任务系统
下面展示一个综合运用枚举的实际案例——限时任务的状态管理:
```dart
enum TaskPriority { low, medium, high, urgent }
enum TaskStatus { pending, inProgress, paused, completed, expired }
class Task {
final String id;
final String title;
final TaskPriority priority;
TaskStatus status;
final DateTime deadline;
Task({
required this.id,
required this.title,
required this.priority,
required this.status,
required this.deadline,
});
// 判断任务是否超时
bool get isExpired {
return status != TaskStatus.completed && DateTime.now().isAfter(deadline);
}
// 判断是否需要提醒
bool get shouldRemind {
final now = DateTime.now();
final remaining = deadline.difference(now);
return status == TaskStatus.pending && remaining.inHours < 24;
}
// 获取状态显示名称
String get statusText {
switch (status) {
case TaskStatus.pending: return '待开始';
case TaskStatus.inProgress: return '进行中';
case TaskStatus.paused: return '已暂停';
case TaskStatus.completed: return '已完成';
case TaskStatus.expired: return '已过期';
}
}
// 获取优先级显示颜色
String get priorityColor {
switch (priority) {
case TaskPriority.low: return '灰色';
case TaskPriority.medium: return '蓝色';
case TaskPriority.high: return '橙色';
case TaskPriority.urgent: return '红色';
}
}
}
// 使用示例
void main() {
Task task = Task(
id: '001',
title: '完成技术文档',
priority: TaskPriority.high,
status: TaskStatus.inProgress,
deadline: DateTime.now().add(Duration(hours: 12)),
);
print('任务状态: ${task.statusText}'); // 输出: 任务状态: 进行中
print('优先级颜色: ${task.priorityColor}'); // 输出: 优先级颜色: 橙色
print('需要提醒: ${task.shouldRemind}'); // 输出: 需要提醒: true
}
这个示例展示了枚举在状态管理中的典型用法:定义有限状态、封装业务逻辑、配合 switch 实现多态行为。
枚举是 Dart 编程中提升代码质量的基础工具。它用类型系统约束可能的取值,用语义化的名称增强可读性,用编译时检查消除运行时错误。当遇到"只能用这几个固定值"的场景时,优先考虑枚举——这是写出健壮代码的第一步。

暂无评论,快来抢沙发吧!