跳到主要内容

Comments(注释)

注释用于解释代码、暂时屏蔽代码,或为公开 API 编写可被文档工具读取的说明。Dart 支持单行注释、多行注释和文档注释;注释本身不会作为普通语句执行。

学习 Dart 注释时,重点需要掌握以下问题:

  • ///* ... */ 分别适合什么场景?
  • 多行注释能否嵌套?
  • /// 与普通注释有什么区别?
  • 如何在文档注释中引用代码里的声明?

单行注释

单行注释以 // 开始,到当前行末结束。它适合补充简短说明:

void main() {
// 使用摄氏温度保存当前读数。
const temperature = 26;

print(temperature); // 输出:26
}

注释可以单独占一行,也可以写在语句之后。说明较长时,优先把注释放在相关代码上方,避免代码行过长。

连续使用多个 // 也可以书写多行说明:

// 只有完成验证的用户
// 才能继续提交表单。
const isVerified = true;

多行注释

多行注释以 /* 开始,以 */ 结束,适合跨越多行的说明:

void main() {
/*
* 这里使用固定数据,
* 方便观察示例的输出。
*/
const topics = ['variables', 'operators', 'comments'];

print(topics.length); // 3
}

Dart 的多行注释支持嵌套。外层注释中可以包含完整的内层 /* ... */

void main() {
/* 外层注释开始
/* 内层注释 */
外层注释继续
*/

print('Dart comments');
}

每个 /* 都必须有对应的 */。即使多行注释能够嵌套,也不宜用大段注释长期保留废弃代码;版本控制系统更适合保存代码历史。

TypeScript 对比:TypeScript 同样支持 ///* ... */,但它的多行注释不能像 Dart 一样嵌套。把含有 /* ... */ 的代码包进 TypeScript 多行注释时,内层第一个 */ 就会提前结束注释。

文档注释

文档注释用于描述类、函数、变量等声明。Dart 文档工具可以读取这类注释并生成 API 文档。推荐使用连续的 ///,并把注释放在目标声明之前:

/// 返回两个整数的和。
int add(int left, int right) {
return left + right;
}

void main() {
print(add(2, 3)); // 5
}

文档注释也可以使用 /** ... */,但同一项目中应保持统一风格。普通的 ///* ... */ 注释不会成为声明的 API 文档。

好的文档注释应说明调用者需要知道的信息,例如用途、参数约束、返回结果和可能抛出的异常,而不是逐行复述实现:

/// 从 [scores] 中返回最高分。
///
/// 如果 [scores] 为空,则抛出 [StateError]。
int highestScore(List<int> scores) {
if (scores.isEmpty) {
throw StateError('scores must not be empty');
}

return scores.reduce((highest, score) {
return score > highest ? score : highest;
});
}

void main() {
print(highestScore([78, 95, 86])); // 95
}

这里的空白文档注释行 /// 用于分隔段落。[scores][StateError] 使用方括号引用代码中的名称,生成文档时可以被解析为对应声明的链接。

文档注释支持 Markdown,因此可以使用段落、列表和代码块组织内容。注释仍应保持简洁,让调用者快速看懂 API 的行为。

TypeScript 对比:TypeScript 项目常用 /** ... */ 形式的 JSDoc 描述 API;Dart 通常使用 ///。两者都能承载 Markdown 风格的说明,但 Dart 的 [Name] 是文档注释中引用声明的常用写法,并不等同于 JSDoc 标签。

注释应该解释什么

注释最有价值的用途是补充代码本身难以表达的信息,例如设计原因、业务限制或不直观的边界条件:

double calculateDiscount(int itemCount) {
// 促销规则要求达到 10 件时一次性进入九折档位。
return itemCount >= 10 ? 0.1 : 0;
}

不要用注释重复显而易见的代码:

var count = 0;
count++; // count 加 1

如果代码很难通过命名和结构读懂,应先考虑重命名或拆分逻辑,再用注释解释仍然无法直接表达的原因。

暂时屏蔽代码

注释可以在调试时暂时阻止某段代码参与执行:

void main() {
print('start');
// print('debug details');
print('end');
}

这种做法适合短暂实验。已经确定不再需要的代码应直接删除,而不是长期保留为注释;需要查看旧实现时可以使用版本控制记录。

常见误区

误区一:用普通注释编写 API 文档

// 适合实现说明,但不会被当作声明的文档注释。需要生成 API 文档时,应使用 ////** ... */

误区二:文档注释放在声明之后

文档注释应紧邻并位于所描述的声明之前。放在函数体内或声明之后,只会成为普通说明,无法正确关联到该声明。

误区三:用注释弥补含糊的命名

与其写 var d = 7; // 过期天数,不如直接命名为 var expirationDays = 7;。清晰的代码负责表达“做什么”,注释更适合解释“为什么这样做”。

误区四:长期保留被注释掉的代码

大量失效代码会干扰阅读,也可能逐渐与当前实现脱节。确认不再需要后应删除,并通过版本控制查阅历史。

小结

  • // 注释从当前位置持续到行末,适合简短说明。
  • /* ... */ 可以跨越多行,并且在 Dart 中支持嵌套。
  • ////** ... */ 是文档注释,可由 Dart 文档工具读取;通常优先使用 ///
  • 文档注释中的 [Name] 可以引用代码声明。
  • 注释应重点解释原因、限制和边界条件,不应重复代码已经清楚表达的内容。
  • 临时注释代码适合短期调试,废弃代码应删除并交由版本控制保存历史。