跳到主要内容

Enumerated types(枚举类型)

枚举类型(enumerated type,简称 enum)用于表示一组数量有限、名称固定的值。每个枚举值都是该枚举类型的常量实例,适合状态、方向、权限级别等封闭集合。

声明与使用枚举

enum OrderStatus {
pending,
paid,
shipped,
cancelled,
}

void main() {
OrderStatus status = OrderStatus.pending;

if (status == OrderStatus.pending) {
print('Waiting for payment');
}
}

枚举值通过 EnumName.value 访问。变量类型是 OrderStatus,不能赋入其他枚举的值或普通字符串。

nameindexvalues

所有枚举值都具有 nameindex

enum Direction { north, east, south, west }

void main() {
print(Direction.east.name); // east
print(Direction.east.index); // 1
print(Direction.values); // [Direction.north, ...]
}
  • name 是源代码中声明的名称。
  • index0 开始,按声明顺序排列。
  • 自动生成的静态常量列表 values 按声明顺序包含全部枚举值。

不要把 index 持久化为稳定业务标识。调整枚举顺序会改变索引;需要持久化时,应定义明确的字符串或数值字段。

按名称查找

可以使用 byName() 从名称取得枚举值:

enum LogLevel { debug, info, warning, error }

void main() {
final level = LogLevel.values.byName('warning');
print(level == LogLevel.warning); // true
}

名称不存在时,byName() 会抛出 ArgumentError。外部输入可能无效时,应先查找映射:

final levelsByName = LogLevel.values.asNameMap();
final level = levelsByName['unknown'];
print(level); // null

switch 中使用

枚举集合是封闭的,因此 switch 可以检查是否覆盖了所有值:

enum TrafficLight { red, yellow, green }

String instruction(TrafficLight light) => switch (light) {
TrafficLight.red => 'Stop',
TrafficLight.yellow => 'Wait',
TrafficLight.green => 'Go',
};

列出所有枚举值后不需要 default。以后新增枚举值时,分析器能提示哪些 switch 尚未处理新情况。

增强枚举

Dart 2.17 起,枚举可以拥有字段、常量构造函数和实例成员:

enum Planet {
mercury(3.303e23, 2.4397e6),
earth(5.976e24, 6.37814e6);

final double mass;
final double radius;

const Planet(this.mass, this.radius);

static const double gravitationalConstant = 6.67300e-11;

double get surfaceGravity {
return gravitationalConstant * mass / (radius * radius);
}
}

void main() {
print(Planet.earth.surfaceGravity);
}

枚举值列表必须位于成员声明之前,并用分号分隔。每个值会调用枚举的常量生成式构造函数。

实现接口与排序

增强枚举可以实现接口,也可以应用满足约束的 Mixin:

enum Priority implements Comparable<Priority> {
low(1),
medium(2),
high(3);

final int weight;

const Priority(this.weight);


int compareTo(Priority other) => weight.compareTo(other.weight);
}

void main() {
final priorities = [Priority.high, Priority.low]..sort();
print(priorities); // [Priority.low, Priority.high]
}

增强枚举的限制

枚举实例在编译期固定,因此声明受到约束:

  • 实例字段必须是 final,包括 Mixin 引入的字段。
  • 生成式构造函数必须是 const
  • 工厂构造函数只能返回已经声明的枚举实例。
  • 不能重写 indexhashCode==
  • 枚举自动继承 Enum,不能再通过 extends 选择其他超类。
  • values 是自动生成的静态成员,不能再声明同名成员。

TypeScript 对比:TypeScript enum 在 JavaScript 输出中通常表现为对象和数值或字符串映射。Dart 枚举值是真正的常量对象;增强枚举还能拥有 final 字段、方法并实现接口,两者的运行时模型并不相同。

常见误区

  • 不要依赖 toString() 解析名称,直接使用 name
  • 不要把可变化的 index 当作长期存储格式。
  • byName() 查找失败会抛出异常,不可信输入更适合通过 asNameMap() 查询。
  • 增强枚举的实例集合仍是固定的,不能在运行时创建新的枚举值。

小结

  • 枚举表示封闭且命名明确的值集合,每个枚举值都是常量实例。
  • nameindexvalues 提供名称、顺序与全集信息。
  • 枚举结合穷尽 switch 能在新增状态时得到静态检查。
  • 增强枚举可以拥有不可变字段、常量构造函数、方法和接口实现。
  • 对外持久化时应使用自定义稳定标识,而不是依赖声明顺序。