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,不能赋入其他枚举的值或普通字符串。
name、index 与 values
所有枚举值都具有 name 和 index:
enum Direction { north, east, south, west }
void main() {
print(Direction.east.name); // east
print(Direction.east.index); // 1
print(Direction.values); // [Direction.north, ...]
}
name是源代码中声明的名称。index从0开始,按声明顺序排列。- 自动生成的静态常量列表
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。 - 工厂构造函数只能返回已经声明的枚举实例。
- 不能重写
index、hashCode和==。 - 枚举自动继承
Enum,不能再通过extends选择其他超类。 values是自动生成的静态成员,不能再声明同名成员。
TypeScript 对比:TypeScript
enum在 JavaScript 输出中通常表现为对象和数值或字符串映射。Dart 枚举值是真正的常量对象;增强枚举还能拥有final字段、方法并实现接口,两者的运行时模型并不相同。
常见误区
- 不要依赖
toString()解析名称,直接使用name。 - 不要把可变化的
index当作长期存储格式。 byName()查找失败会抛出异常,不可信输入更适合通过asNameMap()查询。- 增强枚举的实例集合仍是固定的,不能在运行时创建新的枚举值。
小结
- 枚举表示封闭且命名明确的值集合,每个枚举值都是常量实例。
name、index和values提供名称、顺序与全集信息。- 枚举结合穷尽
switch能在新增状态时得到静态检查。 - 增强枚举可以拥有不可变字段、常量构造函数、方法和接口实现。
- 对外持久化时应使用自定义稳定标识,而不是依赖声明顺序。