A Cláusula Where
Parte da seção Programação Orientada a Objetos do Journey de Rust da Coddy. Lição 42 de 61.
À medida que você adiciona mais limites de traits, as assinaturas de funções podem se tornar difíceis de ler. Considere uma função com vários parâmetros genéricos, cada um exigindo várias traits:
fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
// ...
}
Isso funciona, mas a assinatura está ficando sobrecarregada. A cláusula where oferece uma alternativa mais limpa, movendo os limites de traits para depois da lista de parâmetros:
fn complex_operation<T, U>(first: T, second: U)
where
T: Display + Clone,
U: Debug + Summary,
{
// ...
}
Ambas as versões são funcionalmente idênticas: a cláusula where diz respeito apenas à legibilidade. Os requisitos de cada tipo aparecem em sua própria linha, facilitando verificar o que cada parâmetro genérico precisa.
A cláusula where torna-se especialmente valiosa quando os limites são complexos ou quando você tem muitos parâmetros genéricos. Ela mantém o nome e os parâmetros da função visíveis rapidamente, com as restrições listadas separadamente abaixo. Esse é o estilo preferido na maioria das bases de código Rust quando os limites vão além de um simples T: Trait.
Desafio
FácilVamos construir um sistema de processamento de dados que usa a cláusula where para manter limites complexos de traits legíveis! Você criará uma função genérica com vários parâmetros de tipo, cada um exigindo traits diferentes, e organizará os limites de forma clara usando a sintaxe where.
Você organizará seu código em dois arquivos:
processor.rs: Defina duas traits públicas e uma função genérica que use ambas:Summarize: uma trait com um métodosummaryque recebe&selfe retorna umaStringValidate: uma trait com um métodovalidateque recebe&selfe retorna umbool
process_itemsque aceite dois parâmetros de tipos genéricos diferentes. Use uma cláusulawherepara especificar que o primeiro tipo deve implementar tantoClonequantoSummarize, enquanto o segundo tipo deve implementarValidate. A função deve imprimir o resumo do primeiro item e, em seguida, imprimir se o segundo item é válido.main.rs: Crie duas structs públicas que implementem as traits necessárias:Article: com um campo públicotitle(String). ImplementeSummarizepara retornarArticle: {title}e deriveClone.Form: com um campo públicofilled(bool). ImplementeValidatepara retornar o valor defilled.
process_itemscom ambos.
A cláusula where torna a assinatura da sua função muito mais limpa do que colocar todos os limites entre os sinais de menor e maior. Os requisitos de cada tipo aparecem em sua própria linha, facilitando a visualização do que cada parâmetro genérico precisa.
Sua saída deve mostrar o resumo seguido do resultado da validação:
Article: {title}
Valid: {true/false}Por exemplo, com as entradas Rust Tips e true:
Article: Rust Tips
Valid: trueE com as entradas Breaking News e false:
Article: Breaking News
Valid: falseVocê receberá duas entradas: o título do artigo e se o formulário está preenchido (faça o parsing como bool).
Experimente você mesmo
mod processor;
use processor::{Summarize, Validate, process_items};
use std::io;
// TODO: Defina uma struct pública Article com um campo público title (String)
// Derive Clone para Article
// TODO: Implemente Summarize para Article
// O método summary deve retornar "Article: {title}"
// TODO: Defina uma struct pública Form com um campo público filled (bool)
// TODO: Implemente Validate para Form
// O método validate deve retornar o valor de filled
fn main() {
let mut title = String::new();
io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut filled_input = String::new();
io::stdin().read_line(&mut filled_input).expect("Failed to read line");
let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");
// TODO: Crie um Article com o title fornecido
// TODO: Crie um Form com o valor filled fornecido
// TODO: Chame process_items com o article e form
}
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