AnyCompiler

Traits

A trait defines a set of methods a type can implement — similar to an interface in other languages. Once a type implements a trait, you can call that trait's methods on it directly.

trait Greet {
    fn greet(&self) -> String;
}

struct Person {
    name: String,
}

impl Greet for Person {
    fn greet(&self) -> String {
        format!("Hello, my name is {}", self.name)
    }
}

fn main() {
    let alice = Person { name: String::from("Alice") };
    println!("{}", alice.greet());
}
Output
Hello, my name is Alice

Trait bounds

A generic function can require that its type parameter implements a particular trait, written T: Greet. This lets greet_everyone accept a slice of any type that implements Greet, not just Person specifically — the function is written once and works for every type that satisfies the bound.

trait Greet {
    fn greet(&self) -> String;
}

struct Person {
    name: String,
}

impl Greet for Person {
    fn greet(&self) -> String {
        format!("Hello, my name is {}", self.name)
    }
}

fn greet_everyone<T: Greet>(items: &[T]) {
    for item in items {
        println!("{}", item.greet());
    }
}

fn main() {
    let people = vec![
        Person { name: String::from("Alice") },
        Person { name: String::from("Bob") },
    ];
    greet_everyone(&people);
}
Output
Hello, my name is Alice
Hello, my name is Bob

Next: generics — writing a function or struct that works across many types, the general mechanism trait bounds build on.

Practice exercise

Define a trait Area with a method area(&self) -> f64. Implement it for a struct Square { side: f64 } so that area() returns side * side. Create a Square with side 4.0 and print its area().