以下内容来自 Dart 官方规范
良好的代码风格是优秀代码中一个非常重要的部分。一致的命名、排序和格式有助于使相同的代码看起来相同。它利用了我们大多数人的视觉系统中拥有的强大模式匹配硬件。如果我们在整个 Dart 生态系统中使用一致的风格,那么我们所有人都可以更轻松地学习和贡献彼此的代码。
身份标识
Dart 中的标识符有三种形式。
- 类名称将每个单词的首字母大写,包括第一个。(大驼峰)
- lowerCamelCase名称将每个单词的首字母大写,但第一个单词除外,即使是首字母缩略词,第一个单词也始终小写。
- lowercase_with_underscores名称仅使用小写字母,即使是首字母缩略词也是如此,并且使用 分隔单词_。
类、枚举类型、typedef 和类型参数
每个单词的首字母大写(包括第一个单词),并且不使用分隔符。
✅ 正确写法
class SliderMenu { ... }
class HttpRequest { ... }
定义函数指针类型
typedef Predicate<T> = bool Function(T value);
甚至包括旨在用于元数据注释的类。
✅ 正确写法
class Foo {
const Foo([Object? arg]);
}
@Foo(anArg)
class A { ... }
@Foo()
class B { ... }
如果注释类的构造函数不采用任何参数,您可能需要lowerCamelCase为其创建一个单独的常量。
✅ 推荐写法
const foo = Foo();
@foo
class C { ... }
使用 DO 名称扩展 UpperCamelCase
与类型一样,扩展名应该将每个单词的首字母大写(包括第一个单词),并且不使用分隔符。
✅ 正确写法
extension MyFancyList<T> on List<T> { ... }
extension SmartIterable<T> on Iterable<T> { ... }
包、目录、源文件
请使用以下方式命名命名包、目录、源文件 lowercase_with_underscores
有些文件系统不区分大小写,因此许多项目要求文件名全部为小写。使用分隔符可使名称在该格式下仍可读。使用下划线作为分隔符可确保名称仍然是有效的 Dart 标识符,如果该语言以后支持符号导入,这可能会有所帮助。
✅ 正确写法
my_package
└─ lib
└─ file_system.dart
└─ slider_menu.dart
❌ 错误写法
mypackage
└─ lib
└─ file-system.dart
└─ SliderMenu.dart
导入前缀
使用以下方式命名导入前缀
✅ 正确写法
import 'dart:math' as math;
import 'package:angular_components/angular_components.dart' as angular_components;
import 'package:js/js.dart' as js;
❌ 错误写法
import 'dart:math' as Math;
import 'package:angular_components/angular_components.dart' as angularComponents;
import 'package:js/js.dart' as JS;
类成员、顶级定义、变量、参数、命名参数
应将除第一个单词之外的每个单词的首字母大写,并且不使用分隔符。
✅ 正确写法
var count = 3;
HttpRequest httpRequest;
void align(bool clearItems) {
// ...
}
常量命名
在新代码中,用于 lowerCamelCase
常量变量,包括枚举值。
推荐使用lowerCamelCase
用于常量命名
✅ 正确写法
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
class Dice {
static final numberGenerator = Random();
}
❌ 错误写法
const PI = 3.14;
const DefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');
class Dice {
static final NUMBER_GENERATOR = Random();
}
您可以使用SCREAMING_CAPS
它来与现有代码保持一致,如以下情况:
- 当向已经使用的文件或库中添加代码时
SCREAMING_CAPS
。 - 生成与 Java 代码并行的 Dart 代码时 - 例如,从protobufs 生成的枚举类型。
笔记
我们最初使用 Java 的SCREAMING_CAPS常量样式。我们出于以下几个原因进行了更改:
- SCREAMING_CAPS在很多情况下看起来很糟糕,特别是 CSS 颜色之类的枚举值。
- 常量通常会更改为最终非常量变量,这需要更改名称。
- values枚举类型上定义的属性是 const 和小写。
超过两个字母的首字母缩略词和缩写大写,例如单词
大写的首字母缩略词可能难以阅读,而多个相邻的首字母缩略词可能会导致名称含糊不清。例如,给定一个标识符HTTPSFTP
,读者无法判断它是指HTTPS
FTP
还是。为了避免这种情况,请像普通单词一样将大多数首字母缩略词和缩写大写。如果是指前者或后者,HTTP
SFTP
则此标识符将是。HttpsFtp``HttpSftp
双字母缩写和首字母缩略词是例外。如果两个字母在英语中都是大写,那么在标识符中使用时它们都应保持大写。否则,将其像单词一样大写。
✅ 正确写法
// Longer than two letters, so always like a word:
Http // "hypertext transfer protocol"
Nasa // "national aeronautics and space administration"
Uri // "uniform resource locator"
Esq // "esquire"
Ave // "avenue"
// Two letters, capitalized in English, so capitalized in an identifier:
ID // "identifier"
TV // "television"
UI // "user interface"
// Two letters, not capitalized in English, so like a word in an identifier:
Mr // "mister"
St // "street"
Rd // "road"
❌ 错误写法
HTTP // "hypertext transfer protocol"
NASA // "national aeronautics and space administration"
URI // "uniform resource locator"
esq // "esquire"
Ave // "avenue"
Id // "identifier"
Tv // "television"
Ui // "user interface"
MR // "mister"
ST // "street"
RD // "road"
当任何形式的缩写出现在 lowerCamelCase 标识符的开头时,将标识符改为小写:
var httpConnection = connect();
var tvSet = Television();
var mrRogers = 'hello, neighbor';
优先使用、_等来表示未使用的回调参数
有时回调函数的类型签名需要一个参数,但回调实现不使用该参数。在这种情况下,将未使用的参数命名为 是惯用的做法。如果函数有多个未使用的参数,请使用额外的下划线以避免名称冲突:、__等。
✅ 正确写法
futureOfVoid.then((_) {
print('Operation complete.');
});
本指南仅适用于匿名函数和本地函数。这些函数通常在上下文中立即使用,其中未使用的参数代表什么很清楚。相比之下,顶级函数和方法声明没有这样的上下文,因此必须命名它们的参数,以便清楚地知道每个参数的用途,即使不使用。
不要对非私有标识符使用前导下划线
Dart 在标识符中使用前导下划线来标记成员和顶级声明为私有。这训练用户将前导下划线与其中一种声明联系起来。他们看到“_”就会认为是“私有的”。
局部变量、参数、局部函数或库前缀没有“私有”的概念。当其中一个名称以下划线开头时,它会向读者发出令人困惑的信号。为避免这种情况,请不要在这些名称中使用前导下划线。
不要使用前缀字母
匈牙利表示法和其他方案诞生于 BCPL 时代,当时编译器无法帮助您理解代码。由于 Dart 可以告诉您声明的类型、范围、可变性和其他属性,因此没有必要将这些属性编码到标识符名称中。
✅ 正确写法
defaultTimeout
❌ 错误写法
kDefaultTimeout
不要明确命名库
从技术上来说,在指令中添加名称library是可行的,但是它是一个遗留功能,不建议这么做。
Dart 根据每个库的路径和文件名为其生成一个唯一的标签。命名库会覆盖此生成的 URI。如果没有 URI,工具可能更难找到相关的主库文件。
✅ 正确写法
/// A really great test library.
@TestOn('browser')
library;
❌ 错误写法
library my_library;
订购
为了保持文件序言的整洁,我们规定了指令出现的顺序。每个“部分”应该用空行分隔。
单个 linter 规则处理所有排序指南:directives_ordering。
应将dart:
导入的内容放在其他导入内容之前
✅ 正确写法
import 'dart:async';
import 'dart:html';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
要将package:导入放在相对导入之前
✅ 正确写法
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'util.dart';
在所有导入之后,在单独的部分中指定导出
✅ 正确写法
import 'src/error.dart';
import 'src/foo_bar.dart';
export 'src/error.dart';
❌ 错误写法
import 'src/error.dart';
export 'src/error.dart';
import 'src/foo_bar.dart';
请按字母顺序对部分进行排序
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'foo.dart';
import 'foo/foo.dart';
import 'package:foo/foo.dart';
import 'package:bar/bar.dart';
import 'foo/foo.dart';
import 'foo.dart';
对所有流程控制语句使用花括号
这样做可以避免悬垂 else问题。
✅ 正确写法
if (isWeekDay) {
print('Bike to work!');
} else {
print('Go dancing or read a book!');
}
例外:一个if
语句没有else
子句,其中整个if
语句和then
主体都适合一行。
在这种情况下,如果你喜欢的话,你可以去掉大括号。
if (arg == null) return defaultValue;
但是,如果流程体超出了一行需要分划请使用大括号:
if (overflowChars != other.overflowChars) {
return overflowChars < other.overflowChars;
}
❌ 错误写法
if (overflowChars != other.overflowChars)
return overflowChars < other.overflowChars;