🎓 A1Learner
🔍
0 of 142 lessons completed

Rust Attributes Basics

An attribute is an instruction for the compiler, written above the code it applies to. It sits inside square brackets with a #, like #[derive(Debug)].

A struct cannot print itself yet

Nothing gives Point a Debug form yet, so the {:?} call is an error. The field-by-field print below is the workaround:

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 3, y: 7 };
    // println!("{:?}", p); // error: Point has no Debug form
    println!("point = ({}, {})", p.x, p.y);
}

derive writes the Debug code

One attribute above the struct asks the compiler to write its Debug form:

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 3, y: 7 };
    println!("{:?}", p);
}

Several traits in one attribute

Clone, Copy and PartialEq can all ride in the same derive. Copy makes the assignment copy the point, so both names stay usable:

#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let a = Point { x: 3, y: 7 };
    let b = a;
    println!("a = {:?} b = {:?}", a, b);
    println!("equal = {}", a == b);
}

#[allow] quiets one warning

An unused function earns a dead_code warning. #[allow(dead_code)] tells the compiler that this one is fine:

#[allow(dead_code)]
fn someday() {
    println!("not yet");
}

fn main() {
    println!("program runs");
}

Example

#[derive(Debug, Clone, PartialEq)]
struct Team {
    name: String,
    wins: u32,
}

fn main() {
    let reds = Team { name: String::from("Reds"), wins: 4 };
    let copy = reds.clone();
    println!("{:?}", reds);
    println!("same team = {}", reds == copy);
}

Key points

  • An attribute changes what the compiler does with the item below it.
  • derive asks the compiler to write a trait for the item below it.
  • One attribute can derive several traits at once, separated by commas.
  • #[allow(name)] switches off one named warning for the item below it.
  • Attributes do their work while compiling, not while the program runs.

In this example, one derive attribute sits above Team. It asks for three traits at once: Debug, Clone, and PartialEq. Debug lets {:?} print the whole struct. Clone makes the copy that clone() returns. PartialEq makes the == test possible, and it answers true. Rust Attributes, in the Intermediate course, goes deeper from here — attributes that mark, switch, and reshape code.

Note

Other languages call similar marks annotations or decorators.

A Rust derive writes real code, not just a label.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does #[derive(Clone)] ask the compiler to do?