文章目录

Dart 枚举:enum 类型

发布于 2026-04-06 05:10:36 · 浏览 11 次 · 评论 0 条

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 编程中提升代码质量的基础工具。它用类型系统约束可能的取值,用语义化的名称增强可读性,用编译时检查消除运行时错误。当遇到"只能用这几个固定值"的场景时,优先考虑枚举——这是写出健壮代码的第一步。

评论 (0)

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

扫一扫,手机查看

扫描上方二维码,在手机上查看本文