Implementando Traits
Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 30 de 61.
Agora que você sabe como definir uma trait, vamos ver como fazer uma struct cumprir esse contrato. Implementar uma trait conecta o requisito abstrato ao comportamento concreto.
A sintaxe utiliza impl TraitName for StructName:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
O bloco impl Speak for Dog informa ao Rust que Dog está implementando a trait Speak. Dentro, você fornece o corpo real do método — é aqui que você define como um cachorro fala.
O poder das traits torna-se claro quando múltiplos tipos implementam a mesma:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
Tanto Dog quanto Cat agora compartilham a capacidade Speak, mas cada um fornece sua própria implementação única. Você pode chamar .speak() em qualquer um dos tipos:
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex diz: Woof!
println!("{}", cat.speak()); // Whiskers diz: Meow!
Esta é a base do polimorfismo em Rust — tipos diferentes, mesma interface, comportamentos únicos.
Desafio
FácilVamos dar vida às traits implementando-as para diferentes tipos! Você criará uma trait Describable e a implementará para duas structs diferentes, cada uma fornecendo sua própria descrição única.
Você organizará seu código em três arquivos:
describable.rs: Defina uma trait públicaDescribablecom um métododescribe(&self) -> String.items.rs: Crie duas structs públicas que implementam sua trait:Bookcom um campo públicotitle(String)Moviecom um campo públiconame(String)
Describablecom seu próprio formato de descrição exclusivo.main.rs: Reúna seus módulos, crie instâncias de ambas as structs e chame seus métodosdescribepara mostrar como a mesma trait produz saídas diferentes para tipos diferentes.
Seu Book deve se descrever como Book: {title} e seu Movie deve se descrever como Film: {name}. Observe como cada tipo cumpre o mesmo contrato, mas com seu próprio comportamento!
No seu arquivo principal, crie um livro e um filme usando as duas entradas fornecidas e, em seguida, imprima suas descrições em linhas separadas.
Sua saída deve seguir este formato:
Book: {title}
Film: {name}Por exemplo, com as entradas 1984 e Inception:
Book: 1984
Film: InceptionVocê receberá duas entradas: um título de livro e um nome de filme.
Folha de consulta
Para implementar uma trait para uma struct, use a sintaxe impl TraitName for StructName:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
Múltiplos tipos podem implementar a mesma trait com comportamentos diferentes:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex diz: Woof!
println!("{}", cat.speak()); // Whiskers diz: Meow!
Isso possibilita o polimorfismo em Rust—diferentes tipos compartilhando a mesma interface com implementações únicas.
Experimente você mesmo
mod describable;
mod items;
use describable::Describable;
use items::{Book, Movie};
fn main() {
// Ler entradas
let mut title = String::new();
std::io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
// TODO: Criar uma instância de Book com o título
// TODO: Criar uma instância de Movie com o nome
// TODO: Imprimir a descrição do livro
// TODO: Imprimir a descrição do filme
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Métodos e Comportamento
Introdução a Blocos de ImplementaçãoO Parâmetro SelfMétodos MutáveisFunções AssociadasMúltiplos Blocos de ImplementaçãoEncadeamento de MétodosRecapitulação - Ações de Retângulo4Projeto: Pet Virtual
Definindo o PetAlimentando o Pet7Traits Padrão
A Trait DebugA Trait DisplayClone e CopyTraits de IgualdadeRecapitulação - Ponto Imprimível10Projeto: Sistema de Documentos
A Trait DrawComponente de Texto2Encapsulamento e Módulos
Fundamentos de MódulosA Palavra-chave PublicCampos PrivadosGettersSettersRecapitulação - Cofre Seguro5Genéricos
Structs GenéricasMétodos GenéricosMúltiplos Tipos GenéricosFunções GenéricasRecapitulação - Ponto de Coordenada8Traits como Restrições
Sintaxe de Restrições de TraitRestrições MúltiplasA Cláusula WhereRetornando Tipos com TraitsRecapitulação - Impressora Genérica11Padrões de Projeto em Rust
Padrão NewtypeComposiçãoA Trait DropFrom e IntoRecapitulação - Mock de Smart Pointer3Enums Avançados
Enums com DadosMétodos em EnumsCorrespondência de Variantes de DadosO Enum Option RevisitadoRecapitulação - Enum Shape6Definição de Traits
O que é uma Trait?Implementando TraitsImplementações PadrãoSobrescrevendo PadrõesTraits com ParâmetrosRecapitulação - Media Player