关于 dart-idiomatic-usage
帮助 Dart 开发者编写惯用的字符串和集合代码,涵盖简洁构造、迭代、类型处理,以及重构旧式集合的步骤。
主要功能
- 01字符串插值与字面量组合
- 02使用展开和控制流构造集合
- 03高效判断空集合并迭代
- 04集合类型转换建议
- 05旧式集合重构清单
适用场景
- 01重构 Dart 代码中的字符串拼接
- 02替换命令式集合构造方式
- 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