第 29 条:遵循 Clippy 的建议
“看起来你在写信。需要什么帮助么?” —— Microsoft Clippit
第 31 条描述了 Rust 工具箱中一些很有用的工具。但是其中一个特别有用且重要的工具值得在这里进行单独的介绍:Clippy。
Clippy 是 Cargo 的一个附加模块(通过 cargo clippy
的方式调用)。它可以针对你的 Rust 使用情况生成涵盖多种类别的警告信息:
- 正确性:关于常见的编程错误的警告。
- 惯用法:关于不完全符合标准 Rust 风格的代码结构的警告。
- 简洁性:指出能让代码更加简洁的可行变更。
- 性能:给出避免不必要的处理或者内存分配的建议。
- 可读性:给出能让代码更易读或者更易懂的建议。
比如,如下这段代码编译是正常的:
#![allow(unused)] fn main() { pub fn circle_area(radius: f64) -> f64 { let pi = 3.14; pi * radius * radius } }
但是 Clippy 会指出这里对 π
的近似赋值是没必要且不准确的:
error: approximate value of `f{32, 64}::consts::PI` found
--> src/main.rs:5:18
|
5 | let pi = 3.14;
| ^^^^
|
= help: consider using the constant directly
= help: for further information visit
https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
= note: `#[deny(clippy::approx_constant)]` on by default
链接中的文档解释了该问题并且给出了优化代码的方式。上述示例可调整为:
#![allow(unused)] fn main() { pub fn circle_area(radius: f64) -> f64 { std::f64::consts::PI * radius * radius } }
正如示例中所展示的,每个 Clippy 警告都会伴随着一个网页的链接来描述问题。链接的网页中会说明为什么目标代码会被认为是不恰当的。这些说明很重要:它们的存在使得你可以自行判断是应该采纳这些建议还是由于特殊的原因而忽略它们。有的时候,说明文本中还会描述一些检查项的已知问题,这些描述会解释一些令人困惑的误报。
如果你认定一些警告信息和自己的代码没有关系,你可以通过添加 #[allow(clippy::some_line)]
来忽略针对特定项的警告,或者在包的顶层(top level)添加 #![allow(clipy::some_lint)]
(多了一个感叹号)来忽略整个 crate 中的相应的警告信息。然而,通常情况下,更建议调整目标代码而非花费很多时间和精力来确认一个警告是否真的是误报。
无论你选择了修复代码还是忽略掉这些警告信息,都应该确保你的代码中没有 Clippy 的警告信息。
这样,当新的警告信息出现时 —— 无论是由于代码发生了变更还是 Clippy 升级后包含了新的检查项 —— 我们就能够及时的关注到。Clippy 也应当被纳入你的持续集成系统中(第 32 条)。
Clippy 的警告信息在你学习 Rust 时特别有帮助,因为它们可以揭示那些被你忽略的细节,并帮助你熟悉 Rust 的惯用法。
本书中提到的很多建议,在 Clippy 中均存在相关的警告信息:
- 第 1 条建议使用更具表现力的类型,而非普通的
bool
类型。Clippy 也会指出在函数参数以及结构体中使用了多个bool
类型的问题。 - 第 3 条包括了一些
Option
及Result
类型的操作。Clippy 会指出一些冗余的代码行为,比如: - 第 3 条还建议了应当在可能时将错误返回给调用方。Clippy 会指出那些没有做到的地方。
- 第 5 条建议应当实现
From
trait 而非Into
trait,Clippy 有同样的建议。 - 第 5 条还描述了显式类型转换,而 Clippy 可以针对如下情况给出警告(但对应的检查项默认是关掉的):
- 第 8 条描述了胖指针类型,有多个 Clippy 的校查项指出了一些非必要的额外的指针间接访问:
- 第 9 条描述了操作
Iterator
实例的诸多方法。Clippy 包含了诸多的可以简化迭代器方法使用的检查项1。 - 第 10 条描述了 Rust 的标准 trait,并且包含了很多 Clippy 也会检查到的对实现的要求:
- 第 18 条建议了减少
panic!
的使用以及相关的一些方法比如expect
,Clippy 也会检查这些。 - 第 21 条表述了引入通配符版本的 crate 是不明智的。Clippy 也同意这一点。
- 第 23 条建议避免通配符导入,与 Clippy 一致。
- [第 24 条]及第 25 条提到同一个 crate 的多个不同版本可以出现在同一个项目的依赖中。Clippy 可以通过配置在出现这种情况时给出警告。
- 第 26 条解释了 Cargo feature 的可累加性,而 Clippy 会警告与此原则相违背的 feature 名称(比如
no_std
)。 - 第 26 条同样解释了一个包的可选依赖项是其 feature 集的一部分。如果存在可以用这种方式来替代的显式的 feature 名称(比如 "use-crate-x")时,Clippy 将给出警告。
- 第 27 条描述了文档注释的惯例,并且 Clippy 会指出如下问题:
上述的信息无疑说明了**阅读 Clippy 的警告信息列表**也是一种有意义的学习方式 —— 包括那些默认禁用的检查的禁用原因,是由于它们太严苛了还是由于它们会产生误报?尽管你可能并不想在你的代码里启用这些检查,但是了解这些检查规则出现的原因将会提升你对 Rust 及其惯用法的理解。
注释
部分检查项列举如下:explicit_counter_loop,explicit_iter_loop,explicit_into_iter_loop,filter_map_identity,from_iter_instead_of_collect,into_iter_on_ref,iter_count,iter_next_loop,iter_not_returning_iterator,manual_filter_map,manual_find_map,map_clone,needless_range_loop,search_is_some,skip_while_next,suspicious_map,unnecessary_filter_map,unnecessary_fold。
原文点这里查看