🎓 A1Learner
🔍

Rust Clippy

Clippy is a set of extra checks, called lints, for clumsy or risky code. One command, `cargo clippy`, runs it.

A famous constant, typed from memory

Clippy knows the famous constants by heart. Type one from memory and it stops the build. This lint is deny by default. So it arrives as an error, not a warning.

let radius = 2.0f32;
let pi = 3.14f32;
let area = pi * radius * radius;

A swap written out by hand

Three lines with a temp variable are a swap wearing a disguise. Clippy spots the shape and names the one-call tool for it:

let temp = first;
first = second;
second = temp;

A loop over a single maybe

An Option holds at most one value. Looping over it is a long way to say "if there is one". Clippy says so:

let prize = Some("book");
for p in prize {
    println!("you won: {p}");
}

Asking the length, meaning emptiness

Comparing a length to zero works, but it makes the reader translate. Clippy points at the word that says it directly:

if name.len() == 0 {
    println!("nothing here");
}

Let Clippy apply the safe fixes

cargo clippy --fix rewrites the fixes Clippy is sure about, straight into your files. On the four lines above, it fixed the swap and the length check itself. It left the constant and the loop alone. Those two need your judgement, not a rewrite.

cargo clippy --fix

One lint you mean to break

Sometimes the rough value is the whole point — a sketch, a teaching example. The allow attribute switches one named lint off for one item, and stays in the code as your written reason:

#[allow(clippy::approx_constant)]
fn rough_pi() -> f32 {
    3.14
}

Example

use std::f32::consts::PI;

fn main() {
    let radius = 2.0f32;
    let area = PI * radius * radius;
    println!("area = {area:.2}");

    let prize = Some("book");
    if let Some(p) = prize {
        println!("you won: {p}");
    }

    let mut first = String::from("blue");
    let mut second = String::from("red");
    std::mem::swap(&mut first, &mut second);
    println!("first = {first}, second = {second}");

    let name = String::new();
    println!("empty = {}", name.is_empty());
}

Key points

  • Clippy: a set of extra checks, called lints, that look for clumsy or risky patterns the compiler itself allows
  • Use cargo clippy to run every check on your project.
  • The messages point at the exact lines.
  • The fix is often written out for you.
  • Every message names its lint, like clippy::manual_swap.
  • The name is a doorway.
  • The message links to a page that explains the rule with examples.
  • Lint levels: warn prints the message and carries on.
  • deny stops the build, like an error.
  • Use #[allow(clippy::name)] above one item to switch a single lint off there.
  • Do it on purpose, in writing, where a reader can see it.
  • If the command is missing, rustup component add clippy installs it.

In this example, every part is the fixed version of a complaint from this lesson. The area uses PI from std::f32::consts — the real constant, not 3.14 typed from memory — and prints area = 12.57. The prize is opened with if let, the honest shape for a single maybe, and prints you won: book. The two names trade places through std::mem::swap, one call instead of the temp-variable dance, so first = red and second = blue. The name is a fresh, empty String. is_empty() says so in one word: empty = true. Run cargo clippy on this program and it reports nothing at all. cargo clippy -- -D warnings passes too. That flag turns every warning into an error.

Note

Clippy arrives with Rust through rustup, next to cargo and rustfmt.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does cargo clippy -- -D warnings do?