ZetCode

Dart 中的枚举类型

最后修改于 2025 年 5 月 25 日

Dart 中的枚举(enumeration)是一种特殊的类,用于表示固定数量的常量值。本教程将涵盖 Dart 的枚举类型,从基本用法到增强枚举和模式匹配等高级功能。

Dart 枚举概述

Dart 的枚举类型允许您定义一组命名常量值。枚举适用于表示一组固定的相关选项,例如一周中的某几天、交通灯的状态或用户角色。Dart 的枚举系统简单而强大,提供了内置的属性和方法,使得处理枚举变得简单高效。

Dart 中的枚举可以是基本的,仅表示一组命名常量;也可以是增强的,可以包含属性、方法和构造函数。Dart 还支持枚举的模式匹配,从而实现简洁且富有表现力的 switch 语句和表达式。

功能 描述 示例
基本枚举 简单的命名常量集 enum Color { red, green, blue }
增强枚举 带有属性和方法的枚举 enum Status { active('A'), inactive('I') }
Switch 匹配 枚举的模式匹配 switch(color) { case Color.red: ... }
枚举属性 内置的索引和名称访问 color.index, color.name

基本枚举声明

Dart 中最简单的枚举形式是声明一组命名常量值。这些枚举适用于表示一组固定的相关选项,其中每个选项同等重要且没有附加数据。

basic_enum.dart
enum Day {
  monday,
  tuesday,
  wednesday,
  thursday,
  friday,
  saturday,
  sunday
}

void main() {
  Day today = Day.friday;
  print('Today is $today');
  print('Day index: ${today.index}');
  print('Day name: ${today.name}');
  
  // Iterate all enum values
  for (var day in Day.values) {
    print('$day (${day.index})');
  }
}

基本枚举会自动获得几个有用的属性。`index` 属性返回枚举值在其声明中的零基位置。`name` 属性返回枚举值的字符串表示。`values` 常量提供了一个按声明顺序排列的所有枚举值的列表。

$ dart run basic_enum.dart
Today is Day.friday
Day index: 4
Day name: friday
Day.monday (0)
Day.tuesday (1)
Day.wednesday (2)
Day.thursday (3)
Day.friday (4)
Day.saturday (5)
Day.sunday (6)

增强枚举

Dart 的增强枚举允许向枚举声明添加属性、方法和构造函数。这项功能使枚举更强大,能够携带附加数据和行为。

enhanced_enum.dart
enum Planet {
  mercury(mass: 3.303e+23, radius: 2.4397e6),
  venus(mass: 4.869e+24, radius: 6.0518e6),
  earth(mass: 5.976e+24, radius: 6.37814e6),
  mars(mass: 6.421e+23, radius: 3.3972e6);
  
  final double mass;
  final double radius;
  double get gravity => 6.67430e-11 * mass / (radius * radius);
  
  const Planet({required this.mass, required this.radius});
  
  String describe() {
    return '$name has mass ${mass.toStringAsExponential(1)} kg '
           'and radius ${radius.toStringAsExponential(1)} m';
  }
}

void main() {
  Planet home = Planet.earth;
  print(home.describe());
  print('Surface gravity: ${home.gravity.toStringAsFixed(2)} m/s²');
  
  // Compare enum values
  if (home == Planet.earth) {
    print('We are on Earth!');
  }
}

增强枚举可以声明由常量构造函数初始化的 final 字段。它们还可以包含 getter 和方法以提供附加功能。每个枚举值都必须使用必需的参数调用构造函数。增强枚举语法在增加显著的表达能力的同时,保持了类型安全。

$ dart run enhanced_enum.dart
earth has mass 6.0e+24 kg and radius 6.4e+6 m
Surface gravity: 9.80 m/s²
We are on Earth!

枚举的模式匹配

Dart 的 switch 表达式和模式匹配与枚举类型特别地配合得很好。这允许对所有可能的枚举值进行详尽检查,并提供编译时安全性。

pattern_matching.dart
enum TrafficLight {
  red,
  yellow,
  green
}

String getTrafficInstruction(TrafficLight light) {
  return switch (light) {
    TrafficLight.red => 'Stop',
    TrafficLight.yellow => 'Caution',
    TrafficLight.green => 'Go',
  };
}

void main() {
  TrafficLight current = TrafficLight.yellow;
  print(getTrafficInstruction(current));
  
  // Exhaustive checking
  for (var light in TrafficLight.values) {
    print('$light: ${getTrafficInstruction(light)}');
  }
}

当使用枚举的 switch 表达式时,Dart 可以确保所有情况都得到处理。如果稍后添加了新的枚举值,编译器会标记任何未处理该值的情况的 switch 语句。这种详尽的检查有助于防止未处理情况导致的运行时错误。模式匹配语法简洁,并清晰地表达了枚举值与其对应行为之间的映射关系。

$ dart run pattern_matching.dart
Caution
TrafficLight.red: Stop
TrafficLight.yellow: Caution
TrafficLight.green: Go

枚举属性和方法

所有 Dart 枚举都自动附带几个有用的属性和方法。这些内置成员使得在没有额外样板代码的情况下轻松使用枚举值。

enum_properties.dart
enum Direction {
  north,
  south,
  east,
  west
}

void main() {
  Direction heading = Direction.east;
  
  // Built-in properties
  print('Index: ${heading.index}');
  print('Name: ${heading.name}');
  
  // Access all values
  print('All directions:');
  for (var dir in Direction.values) {
    print('${dir.name.toUpperCase()} (${dir.index})');
  }
  
  // Convert from string
  String input = 'south';
  Direction? parsed = Direction.values.asNameMap()[input];
  print('Parsed direction: $parsed');
}

`index` 属性返回枚举值在其声明中的零基位置。`name` 属性提供枚举值的字符串表示。静态 `values` 常量包含按声明顺序排列的所有枚举值。`asNameMap()` 方法创建了一个从名称到枚举值的查找表,这对于将字符串解析为枚举值非常有用。

$ dart run enum_properties.dart
Index: 2
Name: east
All directions:
NORTH (0)
SOUTH (1)
EAST (2)
WEST (3)
Parsed direction: Direction.south

将枚举与其他特性混合使用

Dart 枚举与其他语言特性(如泛型、扩展和工厂构造函数)配合良好。这允许强大的组合,可以优雅地解决复杂问题。

mixed_features.dart
enum ApiStatus {
  success,
  failure,
  loading;

  factory ApiStatus.fromCode(int code) {
    return switch (code) {
      200 => ApiStatus.success,
      400 || 500 => ApiStatus.failure,
      _ => ApiStatus.loading,
    };
  }
}

extension ApiStatusExtension on ApiStatus {
  String get message => switch (this) {
    ApiStatus.success => 'Operation succeeded',
    ApiStatus.failure => 'Operation failed',
    ApiStatus.loading => 'Operation in progress',
  };
}

void main() {
  ApiStatus status = ApiStatus.fromCode(200);
  print('Status: ${status.name}');
  print('Message: ${status.message}');
  
  status = ApiStatus.fromCode(500);
  print('Status: ${status.name}');
  print('Message: ${status.message}');
}

枚举中的工厂构造函数支持替代的创建模式,例如从其他数据类型解析。扩展可以在不修改其原始声明的情况下为枚举添加功能。这些特性与模式匹配的结合,产生了干净、可维护的代码,清晰地表达了程序的意图,同时保持了类型安全。

$ dart run mixed_features.dart
Status: success
Message: Operation succeeded
Status: failure
Message: Operation failed

来源

Dart 语言:枚举
Dart 模式匹配

Dart 的枚举类型提供了一种健壮的方法来建模固定集合的相关值。从简单的常量集到具有属性和方法的增强枚举,它们提供不同级别的复杂性以满足您的需求。结合 Dart 的模式匹配功能,枚举在编写清晰、可维护的代码方面变得更加强大。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了超过 1,400 篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出 所有 Dart 教程