现在位置: 首页 > Dart 教程 > 正文

Dart 枚举与符号

枚举(enum)用于定义一组有名字的常量值,让代码更具可读性。

本章介绍 Dart 枚举的定义方式、增强枚举(带方法和属性)以及 Symbol 和 Rune 类型。


enum 枚举定义

枚举是一种特殊的类,用于表示固定数量的常量值。

最典型的场景是表示状态、方向、颜色等有限选项。

实例

// 定义枚举
enum Status {
  pending,    // 待处理
  approved,   // 已批准
  rejected,   // 已拒绝
  cancelled,  // 已取消
}

void main() {
  // 使用枚举值
  Status currentStatus = Status.pending;
  print('当前状态: $currentStatus');

  // 通过 .index 获取索引(从 0 开始)
  print('索引值: ${currentStatus.index}');  // 0

  // 通过 .values 获取所有枚举值
  print('所有状态: ${Status.values}');

  // 遍历所有枚举值
  for (var status in Status.values) {
    print('RUNOOB 状态: $status, 索引: ${status.index}');
  }

  // 通过字符串获取枚举值
  Status parsed = Status.values.byName('approved');
  print('解析出的状态: $parsed');

  // 在 switch 中使用枚举
  switch (currentStatus) {
    case Status.pending:
      print('订单待处理');
      break;
    case Status.approved:
      print('订单已批准');
      break;
    case Status.rejected:
      print('订单被拒绝');
      break;
    case Status.cancelled:
      print('订单已取消');
      break;
  }
}
当前状态: Status.pending
索引值: 0
所有状态: [Status.pending, Status.approved, Status.rejected, Status.cancelled]
RUNOOB 状态: Status.pending, 索引: 0
RUNOOB 状态: Status.approved, 索引: 1
RUNOOB 状态: Status.rejected, 索引: 2
RUNOOB 状态: Status.cancelled, 索引: 3
解析出的状态: Status.approved
订单待处理

枚举和 switch 是绝配。当你在 switch 中处理所有枚举值时,Dart 编译器会检查你是否覆盖了所有情况。这能避免遗漏分支导致的 bug。


增强枚举(带方法和属性)

Dart 3.0 引入了增强枚举(Enhanced Enums),允许枚举拥有字段、方法和构造函数。

实例

// 增强枚举:可以拥有成员变量、构造函数和方法
enum HttpStatus {
  // 枚举值通过构造函数传递参数
  ok(200, '请求成功'),
  created(201, '资源已创建'),
  badRequest(400, '请求错误'),
  unauthorized(401, '未授权'),
  notFound(404, '资源未找到'),
  serverError(500, '服务器内部错误');

  // 成员变量:每个枚举值都有 code 和 message
  final int code;
  final String message;

  // 构造函数:必须是 const
  const HttpStatus(this.code, this.message);

  // 枚举方法
  bool get isSuccess => code >= 200 && code < 300;
  bool get isClientError => code >= 400 && code < 500;
  bool get isServerError => code >= 500;

  // 静态方法:根据状态码查找枚举
  static HttpStatus? fromCode(int code) {
    try {
      return HttpStatus.values.firstWhere((s) => s.code == code);
    } catch (_) {
      return null;
    }
  }
}

void main() {
  var status = HttpStatus.notFound;

  print('RUNOOB HTTP 状态: $status');
  print('状态码: ${status.code}');
  print('消息: ${status.message}');
  print('是否成功: ${status.isSuccess}');
  print('是否客户端错误: ${status.isClientError}');

  // 使用静态方法查找
  var found = HttpStatus.fromCode(201);
  if (found != null) {
    print('找到状态: ${found.message}');
  }

  var unknown = HttpStatus.fromCode(999);
  print('未知状态码: $unknown');
}
RUNOOB HTTP 状态: HttpStatus.notFound
状态码: 404
消息: 资源未找到
是否成功: false
是否客户端错误: true
找到状态: 资源已创建
未知状态码: null

增强枚举让枚举从"命名常量集合"升级为"有行为的类型",可以封装与该枚举相关的逻辑。

增强枚举的构造函数必须是 const,成员变量必须是 final。这是因为枚举值本身就是编译时常量。


Symbol 类型

Symbol 代表 Dart 程序中的标识符(变量名、函数名等)。

它在日常开发中不常用,主要在反射(Reflection)和代码生成场景中使用。

实例

void main() {
  // 使用 # 前缀创建 Symbol
  Symbol sym1 = #runoob;
  Symbol sym2 = #helloWorld;

  print('Symbol 1: $sym1');  // Symbol("runoob")
  print('Symbol 2: $sym2');  // Symbol("helloWorld")

  // Symbol 比较
  Symbol sym3 = #runoob;
  print('sym1 == sym3: ${sym1 == sym3}');  // true

  // Symbol 可以用作 Map 的键
  var metadata = {
    #author: 'RUNOOB',
    #version: '1.0.0',
    #description: 'Dart 教程',
  };
  print('作者: ${metadata[#author]}');
}
Symbol 1: Symbol("runoob")
Symbol 2: Symbol("helloWorld")
sym1 == sym3: true
作者: RUNOOB

Symbol 在 Dart 编译后通常会被压缩(minified),所以不要依赖 Symbol("runoob").toString() 的结果来做逻辑判断。Symbol 的正确用法是通过 dart:mirrors 库进行反射操作。


Rune 与 Unicode

Rune 是 Dart 中表示 Unicode 码点的类型。

在 Dart 中,字符串是 UTF-16 编码的序列。

对于基本多语言平面(BMP)之外的字符(如 emoji),需要使用 Rune 来处理。

实例

void main() {
  // 获取字符串的 Unicode 码点
  String text = 'RUNOOB';
  print('字符: $text');
  print('码点列表: ${text.runes.toList()}');

  // 遍历每个字符和它的码点
  for (var char in text.runes) {
    print('${String.fromCharCode(char)} -> U+${char.toRadixString(16).toUpperCase().padLeft(4, '0')}');
  }

  // 从码点创建字符
  var heart = String.fromCharCode(0x2764);
  print('心形: $heart');

  // 处理多码点字符(如某些 emoji)
  var smile = '\u{1F600}';  // 使用 \u{} 语法表示超出 BMP 的字符
  print('笑脸: $smile');

  // 获取多码点字符的码点
  print('笑脸码点: ${smile.runes.map((r) => 'U+${r.toRadixString(16).toUpperCase()}').toList()}');
}
字符: RUNOOB
码点列表: [82, 85, 78, 79, 79, 66]
R -> U+0052
U -> U+0055
N -> U+004E
O -> U+004F
O -> U+004F
B -> U+0042
心形: &#x2764;
笑脸: &#x1f600;
笑脸码点: [U+1F600]

大部分日常开发中你不需要直接操作 Rune,字符串本身已经能很好地处理 Unicode。

Rune 主要在需要精确操作字符码点时使用,比如文本编辑器、字体渲染等底层场景。