AnyCompiler

Traits

Un trait define un conjunto de métodos que un tipo puede implementar — similar a una interface en otros lenguajes. Una vez que un tipo implementa un trait, puedes llamar a los métodos de ese trait directamente sobre él.

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

Una función genérica puede exigir que su parámetro de tipo implemente un trait en particular, escrito como T: Greet. Esto permite que greet_everyone acepte un slice de cualquier tipo que implemente Greet, no solo Person específicamente — la función se escribe una sola vez y funciona para cualquier tipo que satisfaga el 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

Siguiente: generics — escribir una función o struct que funcione con muchos tipos, el mecanismo general sobre el que se construyen los trait bounds.

Practice Exercise

Define un trait Area con un método area(&self) -> f64. Impleméntalo para un struct Square { side: f64 } de modo que area() devuelva side * side. Crea un Square con side 4.0 e imprime su area().