C.W.K.
Stream
Lesson 01 of 07 · published

Defining and Implementing Traits

~12 min · traits, impl, polymorphism

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

The Types track left you with a generic Point<T> you couldn't do much with — you can't add or print a bare T. Traits are the answer. A trait defines shared behavior that many types can implement, and it's how Rust does polymorphism.

What a trait is

A trait is a set of method signatures a type promises to provide. If you've used interfaces in Java or C#, the shape is familiar — but Rust's traits go further, with default methods, generic bounds, and associated types. You declare one with trait Name { ... }, listing the methods implementors must supply.

Implementing a trait

impl TraitName for TypeName { ... } says 'this type provides this behavior.' One type can implement many traits; one trait can be implemented by many types. That many-to-many web is how Rust composes behavior without inheritance hierarchies.

Traits are shared behavior, not shared data. A struct says what a type is (its fields); a trait says what a type can do (its methods). Rust deliberately separates the two — no base classes, no inheritance trees, just types and the behaviors they opt into.

The coherence rule

One guardrail: you can implement a trait for a type only if you own the trait or the type — the 'orphan rule.' It prevents two crates from implementing the same trait for the same type in conflicting ways. It's why you sometimes wrap a foreign type in your own struct (the newtype pattern) to implement a foreign trait on it.

Code

One trait, two implementors·rust
trait Summary {
    fn summarize(&self) -> String;
}

struct Article { title: String, body: String }
struct Tweet { user: String, text: String }

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{} ({}...)", self.title, &self.body[..self.body.len().min(8)])
    }
}
impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("@{}: {}", self.user, self.text)
    }
}

fn main() {
    let a = Article { title: "Rust".into(), body: "fearless code".into() };
    let t = Tweet { user: "ferris".into(), text: "hi".into() };
    println!("{}", a.summarize());
    println!("{}", t.summarize());
}

External links

Exercise

Define a Describe trait with one method describe(&self) -> String. Implement it for two unrelated structs (say Book and Car). Then write a function that takes a reference to either and prints its description. What did the trait let you do that a concrete type couldn't?
Hint
The trait lets one function accept any type that implements Describe, without knowing the concrete type. That's polymorphism — shared behavior across unrelated types, no inheritance required.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Ttoriwarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.