SyntaxStudy
Sign Up
Rust Defining and Implementing Traits
Rust Beginner 1 min read

Defining and Implementing Traits

A trait defines a set of methods that a type must implement to satisfy the trait contract. Traits are similar to interfaces in Java or abstract base classes in C++, but with important differences: they can have default method implementations, and they can be implemented for types you do not own (the so-called orphan rule applies, but within your crate you can implement any trait for any type). Trait definitions describe what a type can do; they say nothing about the data the type holds. You define a trait with the `trait` keyword and implement it for a type with `impl TraitName for TypeName`. If the trait has default method implementations, you can override them or accept the defaults. A type can implement any number of traits, and a trait can require that implementors also implement other traits (supertraits). Traits are the backbone of Rust's polymorphism story. The standard library is built around core traits: `Iterator`, `Display`, `Debug`, `Clone`, `Copy`, `From`, `Into`, `Eq`, `Ord`, `Hash`, and many more. Understanding these traits and knowing which ones to derive or implement for your types is fundamental to writing idiomatic, interoperable Rust code.
Example
use std::fmt;

// Trait definition with a required method and a default method
trait Animal {
    fn name(&self) -> &str;
    fn sound(&self) -> &str;

    // Default implementation — can be overridden
    fn describe(&self) -> String {
        format!("{} says '{}'", self.name(), self.sound())
    }
}

struct Dog { name: String }
struct Cat { name: String }

impl Animal for Dog {
    fn name(&self) -> &str { &self.name }
    fn sound(&self) -> &str { "woof" }
    // Uses default describe()
}

impl Animal for Cat {
    fn name(&self) -> &str { &self.name }
    fn sound(&self) -> &str { "meow" }

    // Override the default
    fn describe(&self) -> String {
        format!("{} says '{}' and ignores you", self.name(), self.sound())
    }
}

// Display is a standard-library trait
impl fmt::Display for Dog {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Dog({})", self.name)
    }
}

fn print_animal(a: &dyn Animal) {
    println!("{}", a.describe());
}

fn main() {
    let dog = Dog { name: "Rex".to_string() };
    let cat = Cat { name: "Whiskers".to_string() };

    print_animal(&dog);
    print_animal(&cat);
    println!("{dog}");  // uses Display impl

    // Trait objects in a Vec
    let animals: Vec<Box<dyn Animal>> = vec![
        Box::new(Dog { name: "Buddy".to_string() }),
        Box::new(Cat { name: "Luna".to_string() }),
    ];
    for a in &animals {
        println!("{}", a.describe());
    }
}