Esercizio: Usare i tipi composti

Completato

In questo esercizio si useranno i tipi di dati composti per ampliare il programma di una fabbrica di automobili.

Si userà una tupla per tenere traccia della qualità delle auto con due valori correlati, ma con tipi di dati diversi. Verrà creata una funzione denominata car_quality che restituisce questa tupla alla funzione chiamante. La funzione main chiamerà la funzione car_factory per creare ogni ordine di auto.

La sfida consiste nel completare l'esempio di codice in modo che venga compilato ed eseguito.

Per eseguire questo esercizio con il codice di esempio, sono disponibili due opzioni:

  • Copiare il codice e modificarlo nell'ambiente di sviluppo locale.
  • Aprire il codice in un'istanza di Rust Playground preparata.

Nota

Nel codice di esempio cercare la macro todo!. Questa macro indica il codice che deve essere completato o aggiornato.

Aggiornare lo struct Car in modo che abbia un campo di tupla

La prima attività consiste nel cambiare la definizione dello struct Car. Il campo mileage verrà spostato in un campo di tupla denominato age. Oltre al valore del chilometraggio, la tupla age necessita di un altro campo per identificare se l'auto è "nuova" o "usata".

  1. Aprire il primo blocco di codice di esempio.

    Copiare il codice seguente e modificarlo nell'ambiente di sviluppo locale oppure aprire il codice in questo playground Rust preparato.

    #[derive(PartialEq, Debug)]
    // Declare Car struct to describe vehicle with four named fields
    struct Car {
        color: String,
        motor: Transmission,
        roof: bool,
        mileage: u32, // todo!("Move `mileage: u32` field into `age` field - a tuple with two fields: an `Age` enum, u32");
    }
    
    #[derive(PartialEq, Debug)]
    // Declare enum for Car transmission type
    enum Transmission { Manual, SemiAuto, Automatic }
    
  2. Aggiungere un'enumerazione denominata Age con i valori "nuova" e "usata" per descrivere la qualità dell'auto.

  3. Correggere la dichiarazione dello struct Car.

    1. Sostituire il campo mileage: u32 con un campo di tupla denominato age.
    2. Definire la tupla age per avere due campi: un valore di enumerazione Age e il chilometraggio dell'auto.
  4. Compilare il programma. Assicurarsi che il codice venga compilato prima di passare alla sezione successiva.

    Il codice non visualizza ancora alcun output, ma deve essere compilato senza errori. È possibile ignorare i messaggi di avviso del compilatore. Gli avvisi vengono generati perché sono state dichiarate definizioni di enumerazioni e struct, che però non sono state ancora usate.

Creare la funzione car_quality

Successivamente, si aggiungerà il codice per una nuova funzione denominata car_quality. Questa funzione accetta il chilometraggio dell'auto come argomento di input. Verrà creata una tupla per contenere il chilometraggio e l'età dell'auto. La funzione restituirà la tupla al chiamante.

  1. Aggiungere il blocco di codice seguente al codice esistente. È possibile aggiungere il nuovo codice all'inizio o alla fine del file.

    // Get the car quality by testing the value of the input argument
    // - miles (u32)
    // Create a tuple for the car quality with the Age ("New" or "Used") and mileage
    // Return a tuple with the arrow `->` syntax
    fn car_quality (miles: u32) -> (Age, u32) {
    
        // Declare and initialize the return tuple value
        // For a new car, set the miles to 0
        let quality: (Age, u32) = todo!("Set the `Age` value to \"New\", set the mileage using the `miles` input argument");
    
        // Return the completed tuple to the caller
        todo!("Return the tuple");
    }
    
  2. Completare il codice per impostare i valori della tupla quality per un'auto "nuova".

  3. Aggiornare l'istruzione return alla fine della funzione in modo che invii di nuovo la tupla completata al chiamante.

  4. Compilare il programma. Assicurarsi che il codice venga compilato prima di passare alla sezione successiva. Il codice non visualizza ancora alcun output, ma deve essere compilato senza errori.

Aggiornare la funzione car_factory

Il passaggio successivo consiste nell'aggiornare la funzione car_factory. È necessario supportare la tupla restituita dalla funzione car_quality. La definizione dello struct Car è stata aggiornata, quindi è necessario modificare il corpo della funzione per elaborare correttamente i dati.

  1. Aggiungere il blocco di codice seguente al codice esistente. È possibile aggiungere il nuovo codice all'inizio o alla fine del file.

    // Build a new "Car" using the values of four input arguments
    // - color (String)
    // - motor (Transmission enum)
    // - roof (boolean, true if the car has a hard top roof)
    // - miles (u32)
    // Call the car_quality(miles) function to get the car age
    // Return an instance of a "Car" struct with the arrow `->` syntax
    fn car_factory(color: String, motor: Transmission, roof: bool, miles: u32) -> Car {
        // Create a new "Car" instance as requested
        // - Bind first three fields to values of input arguments
        // - "age" field calls "car_quality" function with "miles" input argument 
        Car {
            color: color,
            motor: motor,
            roof: roof,
            mileage: miles, // todo!("Replace `mileage: miles` with `age` tuple field, call `car_quality()` with `miles` as input argument");
        }
    }
    
  2. Correggere l'inizializzazione della variabile car.

    1. Sostituire il campo mileage: miles con un campo di tupla denominato age.
    2. Il campo age deve chiamare la funzione car_quality con l'argomento di input miles.
  3. Compilare il programma. Assicurarsi che il codice venga compilato prima di passare alla sezione successiva.

Impostare le variabili della funzione main

A questo punto è possibile iniziare a usare la funzione main. Il primo passaggio consiste nel definire le variabili che verranno usate nel programma:

  • Una matrice per i colori delle auto
  • Uno struct per ogni ordine di auto
  • Un'enumerazione per descrivere il tipo di trasmissione
  1. Aggiungere il blocco di codice seguente per la funzione main al codice esistente. È possibile aggiungere il nuovo codice all'inizio o alla fine del file.

    fn main() {
        // Create car color array
        let colors = todo!("Set the enum values: 0 = Blue, 1 = Green, 2 = Red, 3 = Silver");
    
        // Declare the car type and initial values
        let mut car: Car = todo!("Create `car` as a `Car` struct");     
        let mut engine: Transmission = todo!("Declare `engine` as a `Transmission` enum, initialize to `Manual`");
    }
    
  2. Completare la definizione per la variabile della matrice colors. Un'auto può essere di quattro colori: blu, verde, rosso o argento.

  3. Correggere la sintassi della dichiarazione per lo struct car e per le variabili dell'enumerazione engine. Inizializzare l'enumerazione engine su "manuale".

    Suggerimento

    Assicurarsi di creare entrambe le variabili come modificabili.

  4. Compilare il programma. Assicurarsi che il codice venga compilato senza errori prima di passare alla sezione successiva.

Chiamare una funzione per evadere gli ordini di auto

Nella funzione main verrà chiamata la funzione car_factory per evadere gli ordini delle auto. La chiamata di funzione prevede un colore per l'auto. È necessario correggere la modalità di indicizzazione nella matrice colors, in modo da passare effettivamente un colore come previsto.

  1. Aggiungere il blocco di codice seguente alla funzione main. Inserire questo codice dopo le definizioni aggiunte nell'ultimo passaggio e prima della parentesi graffa chiusa } per la funzione.

        // Order 3 cars, one car for each type of transmission
    
        // Car order #1: New, Manual, Hard top
        car = car_factory(String::from(todo!("Index into the `colors()` array")), engine, true, 0);
        println!("Car order 1: {:?}, Hard top = {}, {:?}, {}, {} miles", car.age.0, car.roof, car.motor, car.color, car.age.1);
    
        // Car order #2: Used, Semi-automatic, Convertible
        engine = Transmission::SemiAuto;
        car = car_factory(String::from(todo!("Index into the `colors()` array")), engine, false, 100);
        println!("Car order 2: {:?}, Hard top = {}, {:?}, {}, {} miles", car.age.0, car.roof, car.motor, car.color, car.age.1);
    
        // Car order #3: Used, Automatic, Hard top
        engine = Transmission::Automatic;
        car = car_factory(String::from(todo!("Index into the `colors()` array")), engine, true, 200);
        println!("Car order 3: {:?}, Hard top = {}, {:?}, {}, {} miles", car.age.0, car.roof, car.motor, car.color, car.age.1);
    
  2. Correggere l'indicizzazione nella matrice colors nelle chiamate a String::from. La matrice colors ha quattro elementi, quindi provare a usare un colore diverso per ogni ordine.

    Suggerimento

    Gli elementi di una matrice iniziano dalla posizione di indice 0. Il valore per il primo elemento si trova in corrispondenza della posizione di indice 0.

  3. Compilare il programma. Assicurarsi che il codice venga compilato senza errori. È possibile ignorare eventuali messaggi di avviso.

Eseguire il programma

Al termine del programma, l'output dovrà essere simile a questo esempio:

Car order 1: New, Hard top = true, Manual, Blue, 0 miles
Car order 2: New, Hard top = false, SemiAuto, Green, 100 miles
Car order 3: New, Hard top = true, Automatic, Red, 200 miles

Anche se gli ordini 2 e 3 sono per le auto usate, la funzione car_quality restituisce solo New per ora. In un esercizio successivo verrà illustrato come usare le espressioni condizionali per correggere tale problema e per variare gli ordini.

Soluzione

È possibile confrontare l'output del programma con la soluzione per questo esercizio in questa istanza di Rust Playground.