Item 29: Listen to Clippy
"It looks like you're writing a letter. Would you like help?" – Microsoft Clippit
Item 31 describes the ecosystem of helpful tools available in the Rust toolbox, but one tool is sufficiently helpful and important to get promoted to an Item of its very own: Clippy.
Clippy is an additional component for Cargo (cargo clippy
) that emits warnings about your Rust usage, across
a variety of categories:
- Correctness: Warns about common programming errors
- Idiom: Warns about code constructs that aren't quite in standard Rust style
- Concision: Points out variations on the code that are more compact
- Performance: Suggests alternatives that avoid unnecessary processing or allocation
- Readability: Describes alterations to the code that would make it easier for humans to read and understand
For example, the following code builds fine:
#![allow(unused)] fn main() { pub fn circle_area(radius: f64) -> f64 { let pi = 3.14; pi * radius * radius } }
but Clippy points out that the local approximation to π is unnecessary and inaccurate:
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
The linked webpage explains the problem and points the way to a suitable modification of the code:
#![allow(unused)] fn main() { pub fn circle_area(radius: f64) -> f64 { std::f64::consts::PI * radius * radius } }
As shown previously, each Clippy warning comes with a link to a webpage describing the error, which explains why the code is considered bad. This is vital, because it allows you to decide whether those reasons apply to your code or whether there is some particular reason why the lint check isn't relevant. In some cases, the text also describes known problems with the lint, which might explain an otherwise confusing false positive.
If you decide that a lint warning isn't relevant for your code, you can disable it either for that particular item
(#[allow(clippy::some_lint)]
) or for the entire crate (#![allow(clippy::some_lint)]
, with an extra
!
, at the top level). However, it's usually better to take the cost of a minor refactoring of the code than to
waste time and energy arguing about whether the warning is a genuine false positive.
Whether you choose to fix or disable the warnings, you should make your code Clippy-warning free.
That way, when new warnings appear—whether because the code has been changed or because Clippy has been upgraded to include new checks—they will be obvious. Clippy should also be enabled in your CI system (Item 32).
Clippy's warnings are particularly helpful when you're learning Rust, because they reveal gotchas you might not have noticed and help you become familiar with Rust idiom.
Many of the Items in this book also have corresponding Clippy warnings, when it's possible to mechanically check the relevant concern:
- Item 1 suggests using more expressive types than plain
bool
s, and Clippy will also point out the use of multiplebool
s in function parameters and structures. - Item 3 covers manipulations of
Option
andResult
types, and Clippy points out a few possible redundancies, such as the following: - Item 3 also suggests that errors should be returned to the caller where possible; Clippy points out some missing opportunities to do that.
- Item 5 suggests implementing
From
rather thanInto
, which Clippy also suggests. - Item 5 also describes casts, and Clippy has (disabled by default) warnings for the following:
- Item 8 describes fat pointer types, and various Clippy lints point out scenarios where there are unnecessary extra pointer indirections:
- Item 9 describes the myriad ways to manipulate
Iterator
instances; Clippy includes a truly astonishing number of lints that point out combinations of iterator methods that could be simplified. - Item 10 describes Rust's standard traits and included some implementation requirements that Clippy checks:
- Item 18 suggests limiting the use of
panic!
or related methods likeexpect
, which Clippy also detects. - Item 21 observes that importing a wildcard version of a crate isn't sensible; Clippy agrees.
- Item 23 suggests avoiding wildcard imports, as does Clippy.
- Item 24 and Item 25 touch on the fact that multiple versions of the same crate can appear in your dependency graph; Clippy can be configured to complain when this happens.
- Item 26 explains the additive nature of Cargo features, and Clippy includes a warning about "negative" feature
names (e.g.,
"no_std"
) that are likely to indicate a feature that falls foul of this. - Item 26 also explains that a crate's optional dependencies form part of its feature set, and Clippy warns if there
are explicit feature names
(e.g.,
"use-crate-x"
) that could just make use of this instead. - Item 27 describes conventions for documentation comments, and Clippy will also point out the following:
As the size of this list should make clear, it can be a valuable learning experience to read the list of Clippy lint warnings—including the checks that are disabled by default because they are overly pedantic or because they have a high rate of false positives. Even though you're unlikely to want to enable these warnings for your code, understanding the reasons why they were written in the first place will improve your understanding of Rust and its idiom.