Trait con parametri
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 33 di 61.
Finora, i nostri metodi dei trait hanno accettato solo &self come parametro. Ma i metodi dei trait possono accettare parametri aggiuntivi, proprio come i metodi normali. Questo li rende molto più utili per le operazioni del mondo reale.
Quando definisci un trait, puoi includere tutti i parametri necessari nelle firme dei metodi:
trait Calculator {
fn add(&self, a: i32, b: i32) -> i32;
fn multiply(&self, a: i32, b: i32) -> i32;
}
Questo trait Calculator richiede due metodi, ciascuno dei quali accetta due interi oltre a &self. Qualsiasi tipo che implementi questo trait deve fornire entrambe le operazioni con queste firme esatte.
Ecco come una struct potrebbe implementarlo:
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
}
}
Ora puoi usare questi metodi con argomenti:
let calc = BasicCalc;
println!("{}", calc.add(5, 3)); // 8
println!("{}", calc.multiply(4, 7)); // 28
Il trait definisce quali parametri accetta ciascun metodo, mentre l’implementazione definisce come vengono utilizzati quei parametri. Questo consente a tipi diversi di eseguire le stesse operazioni a modo loro: magari un LoggingCalc potrebbe stampare ogni operazione prima di restituire il risultato.
Sfida
FacileCostruiamo un toolkit per la manipolazione delle stringhe in cui diversi processori possono trasformare il testo a modo loro! Creerai un trait TextProcessor con metodi che accettano parametri, poi lo implementerai per due tipi di processore diversi.
Organizzerai il codice in tre file:
processor.rs: Definisci un trait pubblicoTextProcessorcon due metodi che accettano parametri:repeat(&self, text: &str, times: u32) -> String: ripete il testo specificato per un determinato numero di voltetruncate(&self, text: &str, max_len: usize) -> String: accorcia il testo fino alla lunghezza massima specificata
processors.rs: Crea due struct pubbliche che implementano il tuo trait:SimpleProcessor: una struct unitaria che ripete il testo inserendo spazi tra ogni ripetizione (ad esempio, "Hi" ripetuto 3 volte diventa "Hi Hi Hi") e tronca semplicemente il testo al raggiungimento della lunghezza massimaFancyProcessor: una struct unitaria che ripete il testo inserendo " * " tra le ripetizioni (ad esempio, "Hi" ripetuto 3 volte diventa "Hi * Hi * Hi") e tronca il testo aggiungendo "..." se è stato accorciato (solo se il testo originale era più lungo di max_len)
main.rs: Riunisci i tuoi moduli e mostra come gli stessi metodi del trait producono risultati diversi a seconda del processore utilizzato.
Nel file principale, crea entrambi i processori e usa gli input per testarli. Riceverai tre input: una stringa di testo, un numero di ripetizioni e una lunghezza massima.
Stampa quattro righe che mostrino il comportamento di ciascun processore:
Simple repeat: {result}
Simple truncate: {result}
Fancy repeat: {result}
Fancy truncate: {result}Ad esempio, con gli input Hello, 3 e 4:
Simple repeat: Hello Hello Hello
Simple truncate: Hell
Fancy repeat: Hello * Hello * Hello
Fancy truncate: Hell...Nota come entrambi i processori rispettino lo stesso contratto TextProcessor, ma ciascuno trasformi il testo a modo suo. Il trait definisce quali parametri accettano i metodi, mentre ogni implementazione decide come usarli!
Riceverai tre input: il testo da elaborare, il numero di ripetizioni (da analizzare come u32) e la lunghezza massima per il troncamento (da analizzare come usize).
Provalo tu
mod processor;
mod processors;
use processor::TextProcessor;
use processors::{SimpleProcessor, FancyProcessor};
fn main() {
// Leggi gli input
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");
// Crea i processori
let simple = SimpleProcessor;
let fancy = FancyProcessor;
// TODO: Usa i processori per trasformare il testo e stampare i risultati
// Stampa quattro righe:
// Simple repeat: {result}
// Simple truncate: {result}
// Fancy repeat: {result}
// Fancy truncate: {result}
}
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