Traits com Parâmetros
Parte da seção Programação Orientada a Objetos do Journey de Rust da Coddy. Lição 33 de 61.
Até agora, nossos métodos de trait aceitaram apenas &self como parâmetro. Mas os métodos de trait podem aceitar parâmetros adicionais, assim como os métodos comuns. Isso os torna muito mais úteis para operações do mundo real.
Ao definir um trait, você pode incluir todos os parâmetros necessários nas assinaturas dos métodos:
trait Calculator {
fn add(&self, a: i32, b: i32) -> i32;
fn multiply(&self, a: i32, b: i32) -> i32;
}
Este trait Calculator exige dois métodos, cada um aceitando dois inteiros além de &self. Qualquer tipo que implemente este trait deve fornecer ambas as operações com estas assinaturas exatas.
Veja como uma struct poderia implementá-lo:
struct BasicCalc;
impl Calculator for BasicCalc {
fn add(&self, a: i32, b: i32) -> i32 {
a + b
}
fn multiply(&self, a: i32, b: i32) -> i32 {
a * b
}
}
Agora você pode usar esses métodos com argumentos:
let calc = BasicCalc;
println!("{}", calc.add(5, 3)); // 8
println!("{}", calc.multiply(4, 7)); // 28
O trait define quais parâmetros cada método aceita, enquanto a implementação define como esses parâmetros são usados. Isso permite que diferentes tipos realizem as mesmas operações à sua própria maneira: talvez um LoggingCalc pudesse imprimir cada operação antes de retornar o resultado.
Desafio
FácilVamos criar um kit de ferramentas para manipulação de strings, no qual diferentes processadores possam transformar texto de suas próprias maneiras! Você criará um TextProcessor trait com métodos que aceitam parâmetros e, em seguida, o implementará para dois tipos de processadores diferentes.
Você organizará seu código em três arquivos:
processor.rs: Defina um trait públicoTextProcessorcom dois métodos que aceitam parâmetros:repeat(&self, text: &str, times: u32) -> String: repete o texto fornecido um número especificado de vezestruncate(&self, text: &str, max_len: usize) -> String: reduz o texto até o comprimento máximo especificado
processors.rs: Crie duas structs públicas que implementem seu trait:SimpleProcessor: uma unit struct que repete o texto com espaços entre cada repetição (por exemplo, "Hi" repetido 3 vezes se torna "Hi Hi Hi") e trunca simplesmente cortando no comprimento máximoFancyProcessor: uma unit struct que repete o texto com " * " entre as repetições (por exemplo, "Hi" repetido 3 vezes se torna "Hi * Hi * Hi") e trunca adicionando "..." se o texto tiver sido reduzido (somente se o texto original for maior que max_len)
main.rs: Reúna seus módulos e demonstre como os mesmos métodos do trait produzem resultados diferentes com base no processador que você usa.
Em seu arquivo principal, crie ambos os processadores e use as entradas para testá-los. Você receberá três entradas: uma string de texto, uma contagem de repetições e um comprimento máximo.
Imprima quatro linhas mostrando o comportamento de cada processador:
Simple repeat: {result}
Simple truncate: {result}
Fancy repeat: {result}
Fancy truncate: {result}Por exemplo, com as entradas Hello, 3 e 4:
Simple repeat: Hello Hello Hello
Simple truncate: Hell
Fancy repeat: Hello * Hello * Hello
Fancy truncate: Hell...Observe como ambos os processadores cumprem o mesmo contrato de TextProcessor, mas cada um transforma o texto de sua própria maneira! O trait define quais parâmetros os métodos aceitam, enquanto cada implementação decide como usá-los!
Você receberá três entradas: o texto a ser processado, o número de repetições (faça o parse como u32) e o comprimento máximo para truncamento (faça o parse como usize).
Experimente você mesmo
mod processor;
mod processors;
use processor::TextProcessor;
use processors::{SimpleProcessor, FancyProcessor};
fn main() {
// Ler entradas
let mut text = String::new();
std::io::stdin().read_line(&mut text).expect("Failed to read line");
let text = text.trim();
let mut times_input = String::new();
std::io::stdin().read_line(&mut times_input).expect("Failed to read line");
let times: u32 = times_input.trim().parse().expect("Failed to parse times");
let mut max_len_input = String::new();
std::io::stdin().read_line(&mut max_len_input).expect("Failed to read line");
let max_len: usize = max_len_input.trim().parse().expect("Failed to parse max_len");
// Criar processadores
let simple = SimpleProcessor;
let fancy = FancyProcessor;
// TODO: Use os processadores para transformar o texto e imprimir os resultados
// Imprima quatro linhas:
// Simple repeat: {result}
// Simple truncate: {result}
// Fancy repeat: {result}
// Fancy truncate: {result}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
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 PlayerPratique por conta própria: Compilador de Rust online