Menu
Coddy logo textTech

Iterare sugli oggetti trait

Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 47 di 61.

Ora che puoi memorizzare tipi diversi in un Vec<Box<dyn Trait>>, il passo successivo è elaborare quella raccolta. Iterare sugli oggetti trait funziona proprio come iterare su qualsiasi vettore. Scorri ogni elemento e chiami i metodi definiti dal trait.

trait Shape {
    fn area(&self) -> f64;
}

struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }

impl Shape for Circle {
    fn area(&self) -> f64 { 3.14159 * self.radius * self.radius }
}

impl Shape for Rectangle {
    fn area(&self) -> f64 { self.width * self.height }
}

fn main() {
    let shapes: Vec<Box<dyn Shape>> = vec![
        Box::new(Circle { radius: 2.0 }),
        Box::new(Rectangle { width: 3.0, height: 4.0 }),
        Box::new(Circle { radius: 1.0 }),
    ];

    for shape in &shapes {
        println!("Area: {}", shape.area());
    }
}

Quando iteri con for shape in &shapes, ogni shape è un riferimento a un Box<dyn Shape>. Puoi chiamare direttamente qualsiasi metodo del trait Shape: Rust gestisce automaticamente il dispatch dinamico, chiamando l'implementazione corretta per ciascun tipo concreto.

Questo schema è potente per aggregare i risultati. Potresti sommare tutte le aree, filtrare le forme in base alle dimensioni o trasformare la raccolta. L'intuizione chiave è che, una volta inseriti gli elementi in una raccolta di oggetti trait, interagisci con essi esclusivamente tramite l'interfaccia del trait, indipendentemente dai loro tipi sottostanti.

challenge icon

Sfida

Facile

Creiamo un calcolatore dei prezzi per un carrello della spesa che può contenere diversi tipi di articoli! Creerai un sistema in cui prodotti e servizi, ciascuno con una logica di prezzo diversa, possono essere archiviati insieme ed elaborati per calcolare il prezzo totale.

Organizzerai il codice in due file:

  • items.rs: Definisci un trait pubblico Priceable con un metodo price che accetta &self e restituisce un f64. Poi crea due struct pubbliche:
    • Product: con i campi pubblici name (String) e cost (f64). Il suo metodo price deve semplicemente restituire cost.
    • Service: con i campi pubblici name (String), hourly_rate (f64) e hours (f64). Il suo metodo price deve restituire hourly_rate * hours.
  • main.rs: Importa il modulo items e crea un vettore di tipo Vec<Box<dyn Priceable>>. Usa gli input per creare un Product e un Service, aggiungili al vettore, poi scorri la raccolta per calcolare e stampare il prezzo totale di tutti gli articoli.

È qui che gli oggetti trait mostrano tutta la loro potenza. Il codice del ciclo non deve sapere se sta elaborando un Product o un Service. Chiama semplicemente price() su ogni elemento e Rust seleziona automaticamente l'implementazione corretta.

L'output deve mostrare il prezzo totale con due cifre decimali:

Total: ${total}

Ad esempio, con gli input Laptop, 999.99, Consulting, 150.0 e 3.0:

Total: $1449.99

E con gli input Book, 29.99, Tutoring, 50.0 e 2.0:

Total: $129.99

Riceverai cinque input: il nome del prodotto, il costo del prodotto, il nome del servizio, la tariffa oraria e le ore lavorate (analizza i valori numerici come f64).

Provalo tu

mod items;

use items::{Priceable, Product, Service};

fn main() {
    // Leggi i dati in input
    let mut product_name = String::new();
    std::io::stdin().read_line(&mut product_name).expect("Failed to read line");
    let product_name = product_name.trim().to_string();

    let mut product_cost = String::new();
    std::io::stdin().read_line(&mut product_cost).expect("Failed to read line");
    let product_cost: f64 = product_cost.trim().parse().expect("Failed to parse");

    let mut service_name = String::new();
    std::io::stdin().read_line(&mut service_name).expect("Failed to read line");
    let service_name = service_name.trim().to_string();

    let mut hourly_rate = String::new();
    std::io::stdin().read_line(&mut hourly_rate).expect("Failed to read line");
    let hourly_rate: f64 = hourly_rate.trim().parse().expect("Failed to parse");

    let mut hours = String::new();
    std::io::stdin().read_line(&mut hours).expect("Failed to read line");
    let hours: f64 = hours.trim().parse().expect("Failed to parse");

    // TODO: Crea un Product usando product_name e product_cost

    // TODO: Crea un Service usando service_name, hourly_rate e hours

    // TODO: Crea un Vec<Box<dyn Priceable>> e aggiungici entrambi gli elementi

    // TODO: Scorri il vettore e calcola il prezzo totale

    // TODO: Stampa il totale con una cifra decimale
    // Formato: Total: ${total:.1}
}
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore Rust online