[TOC]
>译者注:对于代码规范来说每个语言都有自己的代码规范,很多语言都有通用的代码规范,而Dart也有自己的语言风格约束。本部分翻译难度非常大,有很多难懂的表述,原意翻译加意译,翻译不好忘谅解。仅供参考
好的代码中一个非常重要的部分是好的风格。一致的命名、排版和格式化有助于代码看起来相同。它利用了我们大多数人的视觉系统中强大的模式匹配硬件。如果我们在整个Dart生态系统中使用一致的样式,那么我们所有人都可以更容易地学习和贡献彼此的代码。
## 标识符
标识符有三种类型。
* 大驼峰法:每个单词的首字母大写,包括第一个单词
* 小驼峰法:除了首个单词外每个单词的首字母大写
* 小写加下滑下:全部用小写字母,即使是首字母缩写也需要用下划线分割
### 大驼峰命名法
类、枚举、typedef和类型参数应该大写每个单词的第一个字母(包括第一个单词),并且不使用分隔符。
~~~
class SliderMenu { ... }
class HttpRequest { ... }
typedef Predicate = bool Function<T>(T value);
~~~
甚至包括用于元数据注释的类。
~~~
class Foo {
const Foo([arg]);
}
@Foo(anArg)
class A { ... }
@Foo()
class B { ... }
~~~
如果注释类的构造函数不接受参数,那么您可能需要为它创建一个单独的小写字符常数。
~~~
const foo = Foo();
@foo
class C { ... }
~~~
### 使用小写加下划线来命名库和源文件
有些文件系统不区分大小写,所以许多项目要求文件名都是小写的。使用分隔符可以使名称在那种形式下仍然可读。使用下划线作为分隔符,可以确保名称仍然是有效的Dart标识符,如果后面的语言支持符号导入,这可能会有帮助。
~~~
library peg_parser.source_scanner;
import 'file_system.dart';
import 'slider_menu.dart';
~~~
以下是非常不推荐的写法:
~~~
library pegparser.SourceScanner;
import 'file-system.dart';
import 'SliderMenu.dart';
~~~
>注意:如果您选择命名一个库,这个指南将指定如何命名它。如果您愿意,可以在文件中省略库指令。
>
### 使用小写加下划线来命名导入前缀。
~~~
import 'dart:math' as math;
import 'package:angular_components/angular_components'
as angular_components;
import 'package:js/js.dart' as js;
~~~
以下写法不可取:
~~~
import 'dart:math' as Math;
import 'package:angular_components/angular_components'
as angularComponents;
import 'package:js/js.dart' as JS;
~~~
### 使用小驼峰法命名其他标识符。
类成员、顶级定义、变量、参数和命名参数应该大写每个单词的第一个字母(第一个单词除外),并且不使用分隔符。
~~~
var item;
HttpRequest httpRequest;
void align(bool clearItems) {
// ...
}
~~~
### 优先使用小驼峰法作为常量命名。
在新代码中,对常量变量(包括enum值)使用小驼峰命名法。在使用SCREAMING_CAPS的现有代码中,您可以继续使用所有的caps来保持一致。
~~~
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();
}
~~~
>注意:我们最初对常量使用了Java的SCREAMING_CAPS样式。后来作出了改变,因为:
SCREAMING_CAPS在很多情况下都很糟糕,特别是CSS颜色之类的enum值。
常量经常被更改为最终的非常量变量,这就需要更改名称。
在枚举类型上自动定义的值属性是const和小写的。
### 大写缩写和缩写长于两个字母就像单词那样
大写的首字母缩略词很难读懂,而多个相邻的首字母缩略词可能导致名称不明确。例如,给定一个以HTTPSFTP开头的名称,无法判断它是指HTTPS FTP还是HTTP SFTP。
为了避免这种情况,缩略语和缩略语都像普通的词一样大写,除了两个字母的缩略语。(像ID和Mr这样的两个字母缩写仍然像单词一样大写)。
~~~
HttpConnectionInfo
uiHandler
IOStream
HttpRequest
Id
DB
~~~
不推荐的做法:
~~~
HTTPConnection
UiHandler
IoStream
HTTPRequest
ID
Db
~~~
### 不使用前缀字母
[匈牙利表示法](https://en.wikipedia.org/wiki/Hungarian_notation)和其他方案出现在BCPL时代,那时编译器没有做什么来帮助您理解代码。因为Dart可以告诉您声明的类型、范围、可变性和其他属性,所以没有理由将这些属性编码为标识符名称。
~~~
defaultTimeout
~~~
不推荐的做法:
~~~
kDefaultTimeout
~~~
## 排序
为了使你的文件前言保持整洁,我们有规定的命令,指示应该出现在其中。每个“部分”应该用空行分隔。
### 在其他引入之前引入所需的dart库
~~~
import 'dart:async';
import 'dart:html';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
~~~
### 在相对引入之前先引入在包中的库
~~~
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'util.dart';
~~~
### 第三方包的导入先于其他包
如果您有多个“包”,您可以将您自己的包与其他第三方包一起导入,然后将您的包放在一个单独的部分中。
~~~
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'package:my_package/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';
~~~
## 格式化
与许多语言一样,Dart忽略了空格。然而,程序开发时没有。具有一致的空格样式有助于确保程序开发者看到代码的方式与编译器相同。
### 使用dartfmt格式化代码。
格式化是一项冗长的工作,在重构过程中尤其耗时。幸运的是,你不必为此担心。我们提供一个复杂的自动代码格式器,叫做dartfmt,它可以为您实现这一点。我们有一些关于它适用的规则的文档,但是dartfmt的空格处理规则是Dart的产物。
其余的格式指导方针是针对一些dartfmt不能为您解决的问题。
### 考虑更改代码,使其成为格式友好的代码
格式化程序可以用您向它抛出的任何代码做最好的事情,但是它不能创造奇迹。如果您的代码有特别长的标识符、深度嵌套的表达式、各种不同类型的操作符等,那么格式化的输出可能仍然难以读取。
当这种情况发生时,重新组织或简化代码。考虑缩短局部变量名或将表达式提升为新的局部变量。换句话说,对代码进行同样的修改,就像手工格式化代码并使其更具可读性一样。把达特fmt看作是一种伙伴关系,您可以在其中一起工作,有时是迭代地,以生成漂亮的代码。
### 避免单行超过80个字符
可读性研究表明,长行文本更难阅读,因为当你移动到下一行的开头时,你的眼睛必须移动得更远。这就是为什么报纸和杂志使用多列文本。
如果您真的想要一行超过80个字符,那么我们的经验是,您的代码可能太过冗长,而且可能更紧凑一些。主要的违法者通常是[VeryLongCamelCaseClassNames]。问问你自己,“在那个类型的名字中,每个单词都能告诉我一些关键的东西,或者阻止名字的冲突吗?”如果没有,考虑省略它。
注意,dartfmt为你做了99%,但最后的1%是你。它不会将长字符串文本拆分为80列,因此您必须手动执行。
我们对uri和文件路径进行异常处理。当它们出现在注释或字符串中(通常出现在导入和导出中)时,即使超过了行限制,它们也可能保持在一行上。这使得搜索给定路径的源文件更加容易。
### 对于所有流控制结构,请使用大括号
这样做可以避免悬浮的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;
~~~