• 高效 Dart 语言指南
    • 指南
    • 如何阅读这些指南
    • 术语表
    • 所有准则摘要
      • Style
      • Documentation
      • Usage
      • Design

    高效 Dart 语言指南

    在过去的几年里,我们编写了大量的 Dart 代码,并从中收获了很多经验和教训。我们将与你分享这些经验,这些经验将有助于你编写出一致、健壮、高效的代码。这里包含两主题:

    • 保持一致 当谈论到格式、命名以及参数的相关规则时,哪种规则更好,得出的结论通常是主观且无法达成一致的。但我们知道的是,客观上保持 一致 是非常有益的。

    如果两段代码看起来不同,那它们就应该有不同的含义。当一段突出的代码吸引到你的注意时,那它就应该有吸引你的理由。

    • 保持简洁 Dart 会让开发者感到很亲切,因为它继承了许多与 C、Java、JavaScript 及其他语言相同的语句和表达式语法。我们之所以开发 Dart 语言,是因为这些语言依然有很大的改进的空间。我们提供了很多新的特性,比如字符串插值、初始化范式等,以帮助你更简单、更轻松地表达意图。

    如果有多种方式来描述一件事情,那么你通常应该选择其中最简洁的方式。这并不意味着你要像 Code Golf(代码高尔夫挑战赛)一样将所有代码塞到一行中。而是应该让代码变得 简约 而非 密集

    Dart Analyzer 中有一个 Linter 工具,该工具可以帮助你编写优秀的、一致性的代码。如果存在一个 Linter 规则可以帮助你遵循某个指南准则,那么该指南准则将链接到该规则。比如下面的示例:

    Linter rule: prefer_collection_literals

    更多关于 开启 Linter 规则 的帮助,请查阅 自定义静态分析 文档。

    指南

    为了便于理解,这里我们将指南分成了几个部分:

    • 风格指南 – 该部分定义了布局和组织代码的规则,或者说是 dartfmt 不能为你格式化的那些代码的布局和组织规则。风格指南还为你指定了标识符的格式,比如:驼峰式大小写、下划线的使用等等。

    • 注释指南 – 该部分会告诉你注释中应该包含哪些内容。包括文档注释以及常规的普通代码注释。

    • 使用指南 – 该部分将教你如何充分利用语言特性来实现相关功能。比如你可以在该部分找到如何利用语句或表达式来实现某个功能。

    • 设计指南 – 该部分是最易理解但是覆盖范围最广的。其涵盖了我们所总结的为库设计一致、可用 API 的经验。比如这些 API 的类型签名或声明的说明则会在这里找到。

    有关所有指南的链接,请查阅 概览。

    如何阅读这些指南

    每个指南都分为了几个部分。每个部分包含一些详细的准则。每条准则都以下面其中的一个词作为开头:

    • 准则所描述的内容应该始终被遵守。不应该以任何的理由来偏离违背这些准则。

    • 不要 准则所描述的内容是相反的:描述的准则不是一个好注意。幸运的是,我们不会像其他语言有那么多这样的准则,因为我们没有太多的历史包袱。

    • 推荐 准则所描述的内容 应该 被遵守。但是在有些情况下,可能有更好的或者更合理的做法。请确保在你完全理解准则的情况下,再忽视这些准则。

    • 避免 该单词描述的准则与 “推荐” 描述的准则相反:显然,这些事不应该做,但不排除在极少数场合下有充分的理由可以做。

    • 考虑 准则所描述的内容可以遵守也可以不遵守。取决于具体的情况、习惯做法以及自己的偏好。

    某些准则描述了规则 适用的 例外情况。当这些例外列出时,也有可能不是详尽的—你可能还需要对其它的情况作出判断。

    这听起来好像有点小题大做。其实并没有那么糟糕。大部分的准则都是常识,也符合我们的认知。最终要达到的目标是写出优雅,可读,可维护的代码。

    术语表

    为了使指南保持简洁,我们使用一些简写术语来指代不同的 Dart 结构。

    • 库成员 表示一个顶层字段、Getter 或 Setter 方法、或函数。基本而言,任何顶层的东西都不会是一种类型。

    • 类成员 表示类内部声明的构造函数、字段、Getter 或 Setter 方法、函数或操作符。类成员可以是实例或静态的,也可以是抽象或具体的。

    • 成员 可以表示是一个库成员或者类成员。

    • 变量 通常指的是顶层变量、参数和局部变量。它不包括静态或实例字段。

    • 类型 表示所有命名类型的声明:一个类、typedef 或枚举。

    • 属性 表示顶层变量、Getter 和 Setter 方法(位于类中或顶层,可以是实例或静态的)或字段(实例或静态的)。基本上是任何类似字段的命名结构都可以称为属性。

    所有准则摘要

    Style

    Identifiers

    • DO name types using UpperCamelCase.
    • DO name extensions using UpperCamelCase.
    • DO name libraries, packages, directories, and source files using lowercase_with_underscores.
    • DO name import prefixes using lowercase_with_underscores.
    • DO name other identifiers using lowerCamelCase.
    • PREFER using lowerCamelCase for constant names.
    • DO capitalize acronyms and abbreviations longer than two letters like words.
    • DON’T use a leading underscore for identifiers that aren’t private.
    • DON’T use prefix letters.

    Ordering

    • DO place “dart:” imports before other imports.
    • DO place “package:” imports before relative imports.
    • PREFER placing external “package:” imports before other imports.
    • DO specify exports in a separate section after all imports.
    • DO sort sections alphabetically.

    Formatting

    • DO format your code using dartfmt.
    • CONSIDER changing your code to make it more formatter-friendly.
    • AVOID lines longer than 80 characters.
    • DO use curly braces for all flow control statements.

    Documentation

    Comments

    • DO format comments like sentences.
    • DON’T use block comments for documentation.

    Doc comments

    • DO use /// doc comments to document members and types.
    • PREFER writing doc comments for public APIs.
    • CONSIDER writing a library-level doc comment.
    • CONSIDER writing doc comments for private APIs.
    • DO start doc comments with a single-sentence summary.
    • DO separate the first sentence of a doc comment into its own paragraph.
    • AVOID redundancy with the surrounding context.
    • PREFER starting function or method comments with third-person verbs.
    • PREFER starting variable, getter, or setter comments with noun phrases.
    • PREFER starting library or type comments with noun phrases.
    • CONSIDER including code samples in doc comments.
    • DO use square brackets in doc comments to refer to in-scope identifiers.
    • DO use prose to explain parameters, return values, and exceptions.
    • DO put doc comments before metadata annotations.

    Markdown

    • AVOID using markdown excessively.
    • AVOID using HTML for formatting.
    • PREFER backtick fences for code blocks.

    Writing

    • PREFER brevity.
    • AVOID abbreviations and acronyms unless they are obvious.
    • PREFER using “this” instead of “the” to refer to a member’s instance.

    Usage

    Libraries

    • DO use strings in part of directives.
    • DON’T import libraries that are inside the src directory of another package.
    • PREFER relative paths when importing libraries within your own package’s lib directory.

    Booleans

    • DO use ?? to convert null to a boolean value.

    Strings

    • DO use adjacent strings to concatenate string literals.
    • PREFER using interpolation to compose strings and values.
    • AVOID using curly braces in interpolation when not needed.

    Collections

    • DO use collection literals when possible.
    • DON’T use .length to see if a collection is empty.
    • CONSIDER using higher-order methods to transform a sequence.
    • AVOID using Iterable.forEach() with a function literal.
    • DON’T use List.from() unless you intend to change the type of the result.
    • DO use whereType() to filter a collection by type.
    • DON’T use cast() when a nearby operation will do.
    • AVOID using cast().

    Functions

    • DO use a function declaration to bind a function to a name.
    • DON’T create a lambda when a tear-off will do.

    Parameters

    • DO use = to separate a named parameter from its default value.
    • DON’T use an explicit default value of null.

    Variables

    • DON’T explicitly initialize variables to null.
    • AVOID storing what you can calculate.

    Members

    • DON’T wrap a field in a getter and setter unnecessarily.
    • PREFER using a final field to make a read-only property.
    • CONSIDER using => for simple members.
    • DON’T use this. except to redirect to a named constructor or to avoid shadowing.
    • DO initialize fields at their declaration when possible.

    Constructors

    • DO use initializing formals when possible.
    • DON’T type annotate initializing formals.
    • DO use ; instead of {} for empty constructor bodies.
    • DON’T use new.
    • DON’T use const redundantly.

    Error handling

    • AVOID catches without on clauses.
    • DON’T discard errors from catches without on clauses.
    • DO throw objects that implement Error only for programmatic errors.
    • DON’T explicitly catch Error or types that implement it.
    • DO use rethrow to rethrow a caught exception.

    Asynchrony

    • PREFER async/await over using raw futures.
    • DON’T use async when it has no useful effect.
    • CONSIDER using higher-order methods to transform a stream.
    • AVOID using Completer directly.
    • DO test for Future<T> when disambiguating a FutureOr<T> whose type argument could be Object.

    Design

    Names

    • DO use terms consistently.
    • AVOID abbreviations.
    • PREFER putting the most descriptive noun last.
    • CONSIDER making the code read like a sentence.
    • PREFER a noun phrase for a non-boolean property or variable.
    • PREFER a non-imperative verb phrase for a boolean property or variable.
    • CONSIDER omitting the verb for a named boolean parameter.
    • PREFER the “positive” name for a boolean property or variable.
    • PREFER an imperative verb phrase for a function or method whose main purpose is a side effect.
    • PREFER a noun phrase or non-imperative verb phrase for a function or method if returning a value is its primary purpose.
    • CONSIDER an imperative verb phrase for a function or method if you want to draw attention to the work it performs.
    • AVOID starting a method name with get.
    • PREFER naming a method to_() if it copies the object’s state to a new object.
    • PREFER naming a method as_() if it returns a different representation backed by the original object.
    • AVOID describing the parameters in the function’s or method’s name.
    • DO follow existing mnemonic conventions when naming type parameters.

    Libraries

    • PREFER making declarations private.
    • CONSIDER declaring multiple classes in the same library.

    Classes and mixins

    • AVOID defining a one-member abstract class when a simple function will do.
    • AVOID defining a class that contains only static members.
    • AVOID extending a class that isn’t intended to be subclassed.
    • DO document if your class supports being extended.
    • AVOID implementing a class that isn’t intended to be an interface.
    • DO document if your class supports being used as an interface.
    • DO use mixin to define a mixin type.
    • AVOID mixing in a type that isn’t intended to be a mixin.

    Constructors

    • CONSIDER making your constructor const if the class supports it.

    Members

    • PREFER making fields and top-level variables final.
    • DO use getters for operations that conceptually access properties.
    • DO use setters for operations that conceptually change properties.
    • DON’T define a setter without a corresponding getter.
    • AVOID returning null from members whose return type is bool, double, int, or num.
    • AVOID returning this from methods just to enable a fluent interface.

    Types

    • PREFER type annotating public fields and top-level variables if the type isn’t obvious.
    • CONSIDER type annotating private fields and top-level variables if the type isn’t obvious.
    • AVOID type annotating initialized local variables.
    • AVOID annotating inferred parameter types on function expressions.
    • AVOID redundant type arguments on generic invocations.
    • DO annotate when Dart infers the wrong type.
    • PREFER annotating with dynamic instead of letting inference fail.
    • PREFER signatures in function type annotations.
    • DON’T specify a return type for a setter.
    • DON’T use the legacy typedef syntax.
    • PREFER inline function types over typedefs.
    • CONSIDER using function type syntax for parameters.
    • DO annotate with Object instead of dynamic to indicate any object is allowed.
    • DO use Future<void> as the return type of asynchronous members that do not produce values.
    • AVOID using FutureOr<T> as a return type.

    Parameters

    • AVOID positional boolean parameters.
    • AVOID optional positional parameters if the user may want to omit earlier parameters.
    • AVOID mandatory parameters that accept a special “no argument” value.
    • DO use inclusive start and exclusive end parameters to accept a range.

    Equality

    • DO override hashCode if you override ==.
    • DO make your == operator obey the mathematical rules of equality.
    • AVOID defining custom equality for mutable classes.
    • DON’T check for null in custom == operators.