Implementações Padrão
Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 31 de 61.
Até agora, cada método de trait que definimos foi apenas uma assinatura — um requisito sem corpo. Mas e se a maioria dos tipos que implementam uma trait usasse a mesma lógica? O Rust permite que você forneça uma implementação padrão diretamente na definição da trait.
Em vez de terminar a assinatura do método com um ponto e vírgula, você adiciona um corpo:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
Agora, qualquer tipo que implemente Greet recebe automaticamente este método — sem escrever nenhum código no bloco impl:
struct Guest;
impl Greet for Guest {}
let visitor = Guest;
println!("{}", visitor.greet()); // Olá!
O impl Greet for Guest {} vazio é válido porque a trait já fornece o comportamento. A struct simplesmente "opta por participar" da trait e recebe o método padrão gratuitamente.
Este padrão é útil quando você deseja definir um comportamento compartilhado que funciona para a maioria dos casos. Tipos que precisam de algo diferente podem sobrescrever o padrão (o que você aprenderá a seguir), enquanto tipos que estão satisfeitos com o comportamento padrão não precisam se repetir.
Desafio
FácilVamos explorar o poder das implementações padrão construindo um sistema de notificação! Você criará uma trait que fornece um comportamento padrão pronto para uso, para que os tipos possam aderir sem escrever código repetitivo.
Você organizará seu código em três arquivos:
notifiable.rs: Defina uma trait públicaNotifiablecom um métodonotify(&self) -> Stringque possui uma implementação padrão. O padrão deve retornar"You have a new notification!". Qualquer tipo que implementar esta trait receberá automaticamente este comportamento sem precisar escrever nada em seu bloco impl.alerts.rs: Crie duas structs de unidade públicas simples que implementam sua trait:EmailAlert— implementaNotifiablecom um bloco impl vazio (usa o padrão)SystemAlert— também implementaNotifiablecom um bloco impl vazio (usa o padrão)
main.rs: Reúna seus módulos e demonstre como ambos os tipos de alerta compartilham o mesmo comportamento padrão. Crie instâncias de ambas as structs e chame seus métodosnotify.
Em seu arquivo principal, crie um EmailAlert e um SystemAlert, e então imprima suas notificações em linhas separadas.
Sua saída deve ser:
You have a new notification!
You have a new notification!Observe como ambos os tipos produzem uma saída idêntica — essa é a beleza das implementações padrão! Nenhuma das structs precisou escrever nenhum código para o método notify, mas ambas possuem um comportamento de notificação totalmente funcional. Na próxima lição, você aprenderá como sobrescrever esses padrões quando um tipo precisar de um comportamento personalizado.
Folha de consulta
Métodos de trait podem ter implementações padrão ao fornecer um corpo de método em vez de apenas uma assinatura:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
Tipos que implementam a trait recebem automaticamente o comportamento padrão sem escrever nenhum código:
struct Guest;
impl Greet for Guest {}
let visitor = Guest;
println!("{}", visitor.greet()); // Hello there!
Um bloco impl vazio é válido quando a trait fornece implementações padrão. Isso permite que os tipos optem por um comportamento compartilhado sem repetição.
Experimente você mesmo
mod notifiable;
mod alerts;
use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};
fn main() {
// TODO: Criar uma instância de EmailAlert
// TODO: Criar uma instância de SystemAlert
// TODO: Imprimir a notificação de EmailAlert
// TODO: Imprimir a notificação de SystemAlert
}
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