AnyCompiler

Traits

Um trait define um conjunto de métodos que um tipo pode implementar — similar a uma interface em outras linguagens. Uma vez que um tipo implementa um trait, você pode chamar os métodos desse trait diretamente nele.

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

Uma função genérica pode exigir que seu parâmetro de tipo implemente um trait específico, escrito como T: Greet. Isso permite que greet_everyone aceite um slice de qualquer tipo que implemente Greet, não só Person especificamente — a função é escrita uma única vez e funciona para todo tipo que satisfaça o 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

Próximo: generics — escrever uma função ou struct que funcione com muitos tipos, o mecanismo geral sobre o qual os trait bounds são construídos.

Practice Exercise

Defina um trait Area com um método area(&self) -> f64. Implemente-o para um struct Square { side: f64 } de modo que area() retorne side * side. Crie um Square com side 4.0 e imprima seu area().