mcpField
D
dart-idiomatic-usage

dart-idiomatic-usage

github.com/dart-lang开发53266 次安装2 周前更新
代码仓库

关于 dart-idiomatic-usage

帮助 Dart 开发者编写惯用的字符串和集合代码,涵盖简洁构造、迭代、类型处理,以及重构旧式集合的步骤。

主要功能

  1. 01字符串插值与字面量组合
  2. 02使用展开和控制流构造集合
  3. 03高效判断空集合并迭代
  4. 04集合类型转换建议
  5. 05旧式集合重构清单

适用场景

  1. 01重构 Dart 代码中的字符串拼接
  2. 02替换命令式集合构造方式
  3. 03更新旧式集合操作与类型转换

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dart-lang/skills --skill dart-idiomatic-usage

安装后在 Claude Code 中输入/dart-idiomatic-usage确认已加载。

详细介绍

编写符合 Dart 惯用风格的集合与字符串

目录

字符串拼接

遵循以下实践,高效且清晰地拼接字符串。

  • 使用相邻字符串进行拼接: 不要使用 + 运算符拼接字符串字面量。将它们相邻放置,即可组成一个字符串。
  • 优先使用字符串插值: 使用 $variable 或 ${expression} 拼接字符串和值,而不是使用(+)进行拼接。
  • 省略不必要的花括号: 插值简单标识符且其后不紧跟字母或数字时,使用 $identifier 而不是 ${identifier}。
示例

正确:

// Adjacent strings
raiseAlarm(
  'ERROR: Parts of the spaceship are on fire. Other '
  'parts are overrun by martians. Unclear which are which.',
);

// Interpolation without unnecessary braces
var greeting = 'Hi, $name! I love your ${decade}s costume.';

错误:

// Do not use + for literals or variables
raiseAlarm(
  'ERROR: Parts of the spaceship are on fire. Other ' +
  'parts are overrun by martians. Unclear which are which.',
);

var greeting = 'Hi, ' + name + '! I love your ' + decade.toString() + 's costume.';
var badBraces = 'Hi, ${name}!';

集合初始化

利用 Dart 内置语法创建和组织集合。

  • 使用集合字面量: 使用 []、{} 和 <Type>{} 实例化列表、映射和集合,而不是使用它们不带名称的构造函数(例如 Map()、Set())。
  • 使用展开和控制流运算符: 使用展开运算符(...、...?)和集合 if/for 构建动态集合,而不是使用命令式的 add() 或 addAll() 调用。
示例

正确:

var points = <Point>[];
var addresses = <String, Address>{};

var arguments = [
  ...options,
  command,
  ...?modeFlags,
  for (var path in filePaths)
    if (path.endsWith('.dart')) path.replaceAll('.dart', '.js'),
];

错误:

var addresses = Map<String, Address>();

var arguments = <String>[];
arguments.addAll(options);
arguments.add(command);
if (modeFlags != null) arguments.addAll(modeFlags);

集合操作

优化集合查询和迭代。

  • 使用 .isEmpty 和 .isNotEmpty: 绝不通过检查集合的 .length 是否为 0 或大于 0 来判断。Iterable 契约并不保证计算长度的时间复杂度为常数。
  • 避免使用函数字面量调用 Iterable.forEach(): 遍历序列时使用标准的 for-in 循环。仅在传递已有函数 tear-off 时使用 forEach()(例如 people.forEach(print))。
  • 使用 whereType<T>(): 使用内置的 whereType<T>() 方法按类型筛选集合,而不是使用 where((e) => e is T)。
示例

正确:

if (lunchBox.isEmpty) return 'so hungry...';

for (final person in people) {
  process(person);
}

var ints = objects.whereType<int>();

错误:

if (lunchBox.length == 0) return 'so hungry...';

people.forEach((person) {
  process(person);
});

var ints = objects.where((e) => e is int).cast<int>();

集合中的类型转换

尽量少用 .cast<T>(),因为它会创建惰性集合,并在每次操作时检查元素类型,从而降低性能。

  • 使用正确的类型创建: 实例化集合时,为其定义正确的泛型类型。
  • 使用 List.from() 进行急切类型转换: 如果必须转换集合且会访问其中大部分元素,请使用 List<T>.from(iterable) 或 Map<K, V>.from(map),一次性急切转换所有元素。
  • 使用 .toList() 保留类型: 如果要复制可迭代对象并保留其原始类型,请使用 .toList()。仅在有意更改类型时使用 List.from()。
示例

正确:

// Eager cast
var stuff = <dynamic>[1, 2];
var ints = List<int>.from(stuff);

// Map with explicit type
var reciprocals = stuff.map<double>((n) => n * 2);

错误:

// Lazy cast (performance hit on every access)
var stuff = <dynamic>[1, 2];
var ints = stuff.toList().cast<int>();

var reciprocals = stuff.map((n) => n * 2).cast<double>();

工作流:重构旧版集合

将旧版 Dart 代码更新为现代标准时,请按顺序遵循以下检查清单。

任务进度
  • 步骤 1:替换构造函数。 搜索 Map()、Set() 和 List()(如适用),并分别替换为 <K, V>{}、<T>{} 和 <T>[]。
  • 步骤 2:移除 .length 检查。 使用正则表达式搜索 .length == 0、.length > 0 和 .length != 0,并替换为 .isEmpty 或 .isNotEmpty。
  • 步骤 3:简化命令式集合构建。 找出对新实例化集合进行的连续 .add() 和 .addAll() 调用,并改用集合字面量中的 ...、if 和 for。
  • 步骤 4:移除 .cast<T>()。 搜索 .cast<。
    • 如果它跟在 .toList() 之后,请替换为 List<T>.from()。
    • 如果它跟在 .where() 之后,请替换为 .whereType<T>()。
    • 如果它跟在 .map() 之后,请将泛型类型添加到 map 调用中:.map<T>(...)。
  • 步骤 5:运行验证器 -> 检查错误 -> 修复。 运行 dart analyze,确保重构没有引入类型提升或语法错误。

评论

支持 Markdown