mcpField
E
effective-dart

effective-dart

github.com/evanca开发663255 次安装3 周前更新
代码仓库

关于 effective-dart

effective-dart 是面向 Dart 和 Flutter 开发者的编码规范技能,整理 Effective Dart 风格、类型、结构、文档和测试建议,也包含代码审查检查项。

主要功能

  1. 01标识符命名规范
  2. 02类型与函数建议
  3. 03格式与文件组织指南
  4. 04文档和测试建议
  5. 05代码审查检查项

适用场景

  1. 01统一 Dart 项目的编码风格
  2. 02检查 Flutter 代码规范
  3. 03审查类型注解与 API 文档

安装

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

$npx skills add https://github.com/evanca/flutter-ai-rules --skill effective-dart

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

详细介绍

Effective Dart 技能

此技能介绍如何遵循 Effective Dart 指南,编写地道、高质量的 Dart 和 Flutter 代码。


1. 命名约定

类别约定示例
类、枚举、typedef、类型参数、扩展UpperCamelCaseMyWidget、UserState
包、目录、源文件lowercase_with_underscoresuser_profile.dart
导入前缀lowercase_with_underscoresimport '...' as my_prefix;
变量、参数、命名参数、函数lowerCamelCaseuserName、fetchData()
  • 将超过两个字母的首字母缩写和缩略词按单词形式书写:用 HttpRequest,不要用 HTTPRequest。
  • 除非缩写比完整术语更常见,否则避免使用缩写。
  • 命名时,优先将最能描述用途的名词放在最后。
  • 在代码中始终使用一致的术语。
  • 遵循类型参数的助记命名约定:E(元素)、K/V(键/值)、T/S/U(泛型类型)。
  • 设计 API 时,可以考虑让代码读起来像一个句子。
  • 非布尔属性或变量优先使用名词短语。
  • 布尔属性或变量优先使用非祈使动词短语;优先使用肯定形式。
  • 命名布尔参数时,可以考虑省略动词。
  • 避免以 get 开头命名函数或方法;如果 API 概念上用于访问属性,优先去掉 get 并使用 getter。

2. 类型和函数

  • 使用类修饰符(final、sealed、interface、base、mixin)控制类是否可以被扩展或实现。
  • 对没有初始化器的变量标注类型。
  • 如果字段和顶层变量的类型不明显,则标注类型。
  • 在函数声明上标注返回类型。
  • 在函数声明上标注参数类型。
  • 对无法推断类型参数的泛型调用,写明类型参数。
  • 推断失败时,使用 dynamic 标注,而不是依赖推断。
  • 不返回值的异步成员应使用 Future<void> 作为返回类型。
  • 对概念上用于访问属性的操作,使用 getter。
  • 对概念上用于更改属性的操作,使用 setter。
  • 使用函数声明将函数绑定到名称。
  • 接收范围参数时,使用起始位置包含、结束位置不包含的约定。
// Prefer: explicit class modifier
final class AppConfig {
  final String apiUrl;
  final int timeout;
  const AppConfig({required this.apiUrl, required this.timeout});
}

// Prefer: sealed for exhaustive pattern matching
sealed class Result<T> {}
class Success<T> extends Result<T> { final T value; Success(this.value); }
class Failure<T> extends Result<T> { final Exception error; Failure(this.error); }

3. 风格

dart format .
  • 使用 dart format 格式化代码;不要手动格式化。
  • 所有流程控制语句都使用花括号。
  • 变量值不会改变时,优先使用 final,而不是 var。
  • 编译时常量使用 const。
  • 为提高可读性,行长优先控制在 80 个字符以内。

4. 导入和文件

  • 不要导入其他包 src 目录中的库。
  • 不要让导入路径进入或离开 lib。
  • 在包内优先使用相对导入路径。
  • 导入路径中不要使用 /lib/ 或 ../。
  • 可以考虑为库文件编写库级文档注释。

5. 结构

  • 让文件专注于单一职责。
  • 限制文件长度,以保持可读性。
  • 将相关功能放在一起。
  • 字段和顶层变量优先声明为 final。
  • 如果类支持,可以考虑将构造函数声明为 const。
  • 优先将声明设为私有——只公开必要内容。

6. 使用模式

// Adjacent string concatenation (not +)
final greeting = 'Hello, '
    'world!';

// Collection literals
final list = [1, 2, 3];
final map = {'key': 'value'};

// Initializing formals
class Point {
  final double x, y;
  Point(this.x, this.y);
}

// Empty constructor body
class Empty {
  Empty();  // not Empty() {}
}

// rethrow to preserve stack trace
try {
  doSomething();
} catch (e) {
  log(e);
  rethrow;
}
  • 使用 whereType<T>() 按类型筛选集合。
  • 为局部变量的 var 和 final 用法遵循一致的规则。
  • 尽可能在字段的声明处初始化字段。
  • 如果重写了 ==,也要重写 hashCode;确保 == 遵循数学上的相等规则。
  • 优先进行特定异常处理:使用 on SomeException catch (e),而不是宽泛的 catch (e) 或 .catchError 处理器。

7. 文档

/// Returns the sum of [a] and [b].
///
/// Throws [ArgumentError] if either value is negative.
int add(int a, int b) { ... }
  • 将注释写成完整句子(首字母大写,以句号结尾)。
  • 对类型和成员使用 /// 文档注释,而非 /* */ 块注释。
  • 优先为公共 API编写文档注释;也可以考虑为私有 API 编写。
  • 文档注释应以单句摘要开头,并将摘要单独成段。
  • 避免与周围上下文重复。
  • 如果主要目的是产生副作用,函数/方法注释应以第三人称动词开头。
  • 如果主要目的是返回值,则应以名词或非祈使动词短语开头。
  • 布尔型变量/属性的注释应以“Whether”开头,后接名词或动名词短语。
  • 在文档注释中使用 [identifier] 引用作用域内的标识符。
  • 使用散文说明参数、返回值和异常(例如,“The [param]”、“Returns”和“Throws”部分)。
  • 将文档注释放在元数据注解之前。
  • 说明代码存在的原因或应如何使用,而不只是说明它的功能。

8. 测试模式

  • 使用 group 和描述性 test 名称为业务逻辑编写单元测试:
import 'package:test/test.dart';

void main() {
  group('CartService', () {
    late CartService cart;

    setUp(() => cart = CartService());

    test('addItem increases item count', () {
      cart.addItem(Product(id: '1', name: 'Widget', price: 9.99));
      expect(cart.items, hasLength(1));
    });

    test('removeItem decreases total price', () {
      final product = Product(id: '1', name: 'Widget', price: 9.99);
      cart.addItem(product);
      cart.removeItem(product.id);
      expect(cart.totalPrice, equals(0.0));
    });
  });
}
  • 使用 testWidgets 和 WidgetTester 编写组件测试:
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('LoginButton shows loading indicator when tapped',
      (WidgetTester tester) async {
    await tester.pumpWidget(const MaterialApp(home: LoginScreen()));
    await tester.tap(find.byType(ElevatedButton));
    await tester.pump();
    expect(find.byType(CircularProgressIndicator), findsOneWidget);
  });
}

9. 代码审查工作流

审查 Dart 代码是否符合 Effective Dart 规范时,Agent 应检查:

  1. 命名——验证所有标识符均遵循第 1 节中的约定。
  2. 类型注解——确认公共 API 参数、返回类型和未初始化变量都带有类型注解。
  3. 类修饰符——验证在适当情况下使用 final、sealed 或 interface。
  4. 文档——确认所有公共成员都带有 /// 文档注释,且注释包含单句摘要。
  5. 风格——运行 dart format --output=none --set-exit-if-changed . 验证格式。
  6. 分析——运行 dart analyze 并确认没有问题。

参考资料

评论

支持 Markdown