La clausola where
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 42 di 61.
Man mano che aggiungi altri vincoli sui trait, le firme delle funzioni possono diventare difficili da leggere. Considera una funzione con più parametri generici, ognuno dei quali richiede diversi trait:
fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
// ...
}
Funziona, ma la firma sta diventando affollata. La clausola where offre un’alternativa più pulita spostando i vincoli sui trait dopo l’elenco dei parametri:
fn complex_operation<T, U>(first: T, second: U)
where
T: Display + Clone,
U: Debug + Summary,
{
// ...
}
Entrambe le versioni sono funzionalmente identiche: la clausola where riguarda esclusivamente la leggibilità. I requisiti di ciascun tipo compaiono su una riga a sé, così è facile scorrere quelli necessari per ogni parametro generico.
La clausola where diventa particolarmente utile quando i vincoli sono complessi o quando hai molti parametri generici. Mantiene il nome della funzione e i parametri visibili a colpo d’occhio, con i vincoli elencati separatamente sotto. Questo è lo stile preferito nella maggior parte delle basi di codice Rust quando i vincoli vanno oltre un semplice T: Trait.
Sfida
FacileCostruiamo un sistema di elaborazione dei dati che usa la clausola where per mantenere leggibili i vincoli complessi sui trait! Creerai una funzione generica con più parametri di tipo, ciascuno dei quali richiede trait diversi, e organizzerai i vincoli in modo chiaro usando la sintassi where.
Organizzerai il codice in due file:
processor.rs: definisci due trait pubblici e una funzione generica che li usa entrambi:Summarize: un trait con un metodosummaryche riceve&selfe restituisce unaStringValidate: un trait con un metodovalidateche riceve&selfe restituisce unbool
process_itemsche accetta due parametri di tipi generici diversi. Usa una clausolawhereper specificare che il primo tipo deve implementare siaClonesiaSummarize, mentre il secondo tipo deve implementareValidate. La funzione deve stampare il riepilogo del primo elemento, quindi indicare se il secondo elemento è valido.main.rs: crea due struct pubbliche che implementano i trait richiesti:Article: con un campo pubblicotitle(String). ImplementaSummarizein modo che restituiscaArticle: {title}, e derivaClone.Form: con un campo pubblicofilled(bool). ImplementaValidatein modo che restituisca il valore difilled.
process_itemscon entrambi.
La clausola where rende la firma della funzione molto più pulita rispetto a inserire tutti i vincoli tra parentesi angolari. I requisiti di ciascun tipo appaiono su una riga separata, così è facile vedere di cosa ha bisogno ogni parametro generico.
L'output deve mostrare il riepilogo seguito dal risultato della convalida:
Article: {title}
Valid: {true/false}Per esempio, con gli input Rust Tips e true:
Article: Rust Tips
Valid: trueE con gli input Breaking News e false:
Article: Breaking News
Valid: falseRiceverai due input: il titolo dell'articolo e se il modulo è compilato (da analizzare come bool).
Provalo tu
mod processor;
use processor::{Summarize, Validate, process_items};
use std::io;
// TODO: Definisci una struct pubblica Article con un campo pubblico title (String)
// Deriva Clone per Article
// TODO: Implementa Summarize per Article
// Il metodo summary deve restituire "Article: {title}"
// TODO: Definisci una struct pubblica Form con un campo pubblico filled (bool)
// TODO: Implementa Validate per Form
// Il metodo validate deve restituire il valore di 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: Crea un Article con il title fornito
// TODO: Crea un Form con il valore filled fornito
// TODO: Chiama process_items con article e form
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Metodi e comportamento
Introduzione ai blocchi implIl parametro selfMetodi mutabiliFunzioni associateBlocchi impl multipliConcatenamento di metodiRiepilogo - Azioni sul rettangolo4Progetto: animale domestico virtuale
Definire l'animaleNutrire l'animale7Trait standard
Il trait DebugIl trait DisplayClone e CopyTrait di uguaglianzaRiepilogo - Punto stampabile10Progetto: sistema di documenti
Il trait DrawComponente di testo2Incapsulamento e moduli
Nozioni di base sui moduliLa parola chiave publicCampi privatiGetterSetterRiepilogo - Armadietto sicuro5Generics
Struct genericheMetodi genericiPiù tipi genericiFunzioni genericheRipasso - Punto di coordinate8I Trait come vincoli
Sintassi dei vincoli sui traitVincoli multipliLa clausola whereRestituire tipi con i traitRiepilogo - Stampante generica11Modelli di progettazione in Rust
Pattern NewtypeComposizioneIl trait DropFrom e IntoRipasso - Mock con smart pointer3Enumerazioni avanzate
Enumerazioni con datiMetodi sulle enumerazioniCorrispondenza delle varianti con datiL'enumerazione Option ripresaRiepilogo - enumerazione Shape6Definizione dei trait
Che cos’è un trait?Implementare i traitImplementazioni predefiniteSovrascrivere le implementazioni predefiniteTrait con parametriRiepilogo - Lettore multimedialeEsercitati da solo: Compilatore Rust online