M Logo
๐Ÿ“ Rust for Beginners ยท Part 18 of 22

Rust Traits Explained: impl for, &impl Trait, Default Methods, derive

November 10, 2026

Welcome to episode 18 of Rust for Beginners, a series for complete beginners (no programming experience needed). In the last video, we used a trait from the colored crate to give strings new methods. Today, we'll learn what traits are, and write our own. Every code block below is the exact code from the video, ready to copy.

1. New project

Let's create a new project called traits, and open it in VS Code.

bash
cargo new traits
cd traits

2. trait

A trait describes behaviour that different types can share. Our Describe trait says: a type that has it must have a describe method, which returns a String.

src/main.rs:

rust
trait Describe {
    fn describe(&self) -> String;
}

struct Dog {
    name: String,
}

struct Car {
    model: String,
    year: u32,
}

impl Describe for Dog {
    fn describe(&self) -> String {
        format!("{} the dog", self.name)
    }
}

impl Describe for Car {
}

fn main() {
    let dog = Dog { name: String::from("Rex") };
    let car = Car { model: String::from("Mini"), year: 2020 };
    println!("{}", dog.describe());
    println!("{}", car.describe());
}

Error:

text
error[E0046]: not all trait items implemented, missing: `describe`
  --> src/main.rs:20:1
   |
 2 |     fn describe(&self) -> String;
   |     ----------------------------- `describe` from trait
...
20 | impl Describe for Car {
   | ^^^^^^^^^^^^^^^^^^^^^ missing `describe` in implementation

Stage A2 โ€“ the Car's impl gets its method

rust
impl Describe for Car {
    fn describe(&self) -> String {
        format!("a {} from {}", self.model, self.year)
    }
}

Output: Rex the dog / a Mini from 2020

3. impl for

We have two very different types: a Dog and a Car. We implement the trait for each, with impl Describe for Dog.

4. Missing

But the Car's implementation is empty. Let's run it.

bash
cargo run

5. Error

Rust says: not all trait items implemented, describe is missing. A trait is a promise, and Rust checks that we keep it.

6. Fix

Let's write describe for the Car too, and run.

bash
cargo run

7. Parameter

Now the useful part. print info accepts any type that implements Describe. Ampersand impl Describe means: a reference to anything with this trait.

rust
trait Describe {
    fn describe(&self) -> String;

    fn shout(&self) -> String {
        self.describe().to_uppercase()
    }
}

struct Dog {
    name: String,
}

struct Car {
    model: String,
    year: u32,
}

impl Describe for Dog {
    fn describe(&self) -> String {
        format!("{} the dog", self.name)
    }
}

impl Describe for Car {
    fn describe(&self) -> String {
        format!("a {} from {}", self.model, self.year)
    }
}

fn print_info(item: &impl Describe) {
    println!("Info: {}", item.describe());
}

fn main() {
    let dog = Dog { name: String::from("Rex") };
    let car = Car { model: String::from("Mini"), year: 2020 };
    print_info(&dog);
    print_info(&car);
    println!("{}", dog.shout());
}

Output: Info: Rex the dog / Info: a Mini from 2020 / REX THE DOG

8. Default

A trait can also have default methods with a body. shout calls describe, and turns it into capital letters. Every type gets it for free.

9. Run B

Let's run it. The same function works for the dog and the car.

bash
cargo run

10. Built-in

Rust's standard library is full of traits. With derive, the compiler writes some for us: Debug for printing, Clone for copying, and PartialEq for comparing with two equals signs.

rust
use std::fmt;

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

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    let a = Point { x: 1, y: 2 };
    let b = a.clone();
    println!("{a:?}");
    println!("{a}");
    println!("Equal? {}", a == b);
}

Output: Point { x: 1, y: 2 } / (1, 2) / Equal? true

11. Display

Display is the trait behind plain curly braces in println. We implement its fmt method, and decide how a Point looks.

12. Run C

Let's run it. The debug form, our own display form, and yes, they're equal.

bash
cargo run

Recap

To recap: a trait defines shared behaviour. impl Trait for Type keeps the promise. ampersand impl Trait accepts any type that has it. Traits can have default methods. And derive implements common traits for us.

ยฉ 2026 All Rights Reserved By Mahmudul Alam