Sobrescrevendo Padrões
Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 32 de 61.
Implementações padrão são convenientes, mas às vezes um tipo precisa de um comportamento que difere do padrão. Quando isso acontece, você pode sobrescrever o padrão fornecendo sua própria implementação no bloco impl.
Basta definir o método com a mesma assinatura, mas incluir sua lógica personalizada:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
Embora Greet forneça um método greet padrão, Robot o substitui inteiramente por sua própria versão. Quando você chama greet() em um Robot, o Rust usa a implementação personalizada:
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unidade 42 online.
Isso oferece flexibilidade — tipos que estão satisfeitos com o padrão não precisam escrever nada, enquanto tipos que precisam de comportamento especializado podem sobrescrever apenas os métodos com os quais se preocupam. A trait ainda garante que cada tipo implementador tenha o método disponível.
Desafio
FácilVamos construir um sistema de notificação onde diferentes tipos de alerta podem personalizar suas mensagens! Você criará uma trait com uma implementação padrão e, em seguida, fará com que um tipo use o padrão enquanto outro o sobrescreve com um comportamento personalizado.
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 retornando"Alert: Something happened!".alerts.rs: Crie duas structs públicas que implementam sua trait de forma diferente:GenericAlert— uma unit struct que usa a notificação padrão (bloco impl vazio)UrgentAlert— uma struct com um campo públicomessage(String) que sobrescreve o padrão para retornar"URGENT: {message}"onde{message}é a sua mensagem armazenada
main.rs: Reúna seus módulos e demonstre ambos os comportamentos. Crie umGenericAlerte umUrgentAlertusando a entrada fornecida e, em seguida, imprima suas notificações.
O ponto principal aqui é que o GenericAlert recebe o comportamento gratuito do padrão, enquanto o UrgentAlert fornece sua própria versão especializada definindo o método em seu bloco impl.
Sua saída deve seguir este formato:
Alert: Something happened!
URGENT: {message}Por exemplo, com a entrada Server is down!:
Alert: Something happened!
URGENT: Server is down!Você receberá uma entrada: a mensagem para o alerta urgente.
Folha de consulta
Você pode sobrescrever as implementações padrão de traits fornecendo sua própria implementação no bloco impl:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unidade 42 online.
Tipos que não precisam de comportamento personalizado podem usar um bloco impl vazio para aceitar a implementação padrão, enquanto tipos que exigem comportamento especializado podem sobrescrever métodos específicos definindo-os com a mesma assinatura.
Experimente você mesmo
mod notifiable;
mod alerts;
use alerts::{GenericAlert, UrgentAlert};
use notifiable::Notifiable;
fn main() {
// Lê a entrada para a mensagem de alerta urgente
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: Criar uma instância de GenericAlert
// TODO: Criar uma instância de UrgentAlert com a mensagem de entrada
// TODO: Imprimir a notificação de GenericAlert
// TODO: Imprimir a notificação de UrgentAlert
}
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