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());
}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);
}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().