Exercício: Usar um mapa de hash para rastrear pedidos

Concluído

Neste exercício, você vai modificar um programa de fábrica de carros para usar um mapa de hash.

Vamos usar a chave de mapa de hash, pares de valor para acompanhar detalhes sobre os pedidos de carro e para exibir a saída. Uma vez mais, o seu desafio é concluir o código de exemplo para que ele seja compilado e executado.

Para trabalhar no código de exemplo deste exercício, você tem duas opções:

  • Copie o código e edite-o em seu ambiente de desenvolvimento local.
  • Abra o código em um Rust Playground preparado.

Observação

No código de exemplo, procure a macro todo!. Essa macro indica o código que precisa ser concluído ou atualizado.

Carregar o programa atual

A primeira etapa é obter o código do programa existente.

  1. Abra o código do programa para edição. O código inclui declarações de tipo de dados e definições para as funções car_quality, car_factory e main.

    Copie o código a seguir e edite-o em seu ambiente de desenvolvimento local
    ou abra o código em um Rust Playground preparado.

    #[derive(PartialEq, Debug)]
    struct Car { color: String, motor: Transmission, roof: bool, age: (Age, u32) }
    
    #[derive(PartialEq, Debug)]
    enum Transmission { Manual, SemiAuto, Automatic }
    
    #[derive(PartialEq, Debug)]
    enum Age { New, Used }
    
    // Get the car quality by testing the value of the input argument
    // - miles (u32)
    // Return tuple with car age ("New" or "Used") and mileage
    fn car_quality (miles: u32) -> (Age, u32) {
    
        // Check if car has accumulated miles
        // Return tuple early for Used car
        if miles > 0 {
            return (Age::Used, miles);
        }
    
        // Return tuple for New car, no need for "return" keyword or semicolon
        (Age::New, miles)
    }
    
    // Build "Car" using input arguments
    fn car_factory(order: i32, miles: u32) -> Car {
        let colors = ["Blue", "Green", "Red", "Silver"];
    
        // Prevent panic: Check color index for colors array, reset as needed
        // Valid color = 1, 2, 3, or 4
        // If color > 4, reduce color to valid index
        let mut color = order as usize;
        if color > 4 {        
            // color = 5 --> index 1, 6 --> 2, 7 --> 3, 8 --> 4
            color = color - 4;
        }
    
        // Add variety to orders for motor type and roof type
        let mut motor = Transmission::Manual;
        let mut roof = true;
        if order % 3 == 0 {          // 3, 6, 9
            motor = Transmission::Automatic;
        } else if order % 2 == 0 {   // 2, 4, 8, 10
            motor = Transmission::SemiAuto;
            roof = false;
        }                            // 1, 5, 7, 11
    
        // Return requested "Car"
        Car {
            color: String::from(colors[(color-1) as usize]),
            motor: motor,
            roof: roof,
            age: car_quality(miles)
        }
    }
    
    fn main() {
        // Initialize counter variable
        let mut order = 1;
        // Declare a car as mutable "Car" struct
        let mut car: Car;
    
        // Order 6 cars, increment "order" for each request
        // Car order #1: Used, Hard top
        car = car_factory(order, 1000);
        println!("{}: {:?}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);
    
        // Car order #2: Used, Convertible
        order = order + 1;
        car = car_factory(order, 2000);
        println!("{}: {:?}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);    
    
        // Car order #3: New, Hard top
        order = order + 1;
        car = car_factory(order, 0);
        println!("{}: {:?}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);
    
        // Car order #4: New, Convertible
        order = order + 1;
        car = car_factory(order, 0);
        println!("{}: {:?}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);
    
        // Car order #5: Used, Hard top
        order = order + 1;
        car = car_factory(order, 3000);
        println!("{}: {:?}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);
    
        // Car order #6: Used, Hard top
        order = order + 1;
        car = car_factory(order, 4000);
        println!("{}: {:?}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);
    }
    
  2. Compile o programa. Verifique se o código é compilado e executado antes de prosseguir para a próxima seção.

Você deve ver o seguinte resultado:

1: Used, Hard top = true, Manual, Blue, 1000 miles
2: Used, Hard top = false, SemiAuto, Green, 2000 miles
3: New, Hard top = true, Automatic, Red, 0 miles
4: New, Hard top = false, SemiAuto, Silver, 0 miles
5: Used, Hard top = true, Manual, Blue, 3000 miles
6: Used, Hard top = true, Automatic, Green, 4000 miles

Adicione um mapa de hash para rastrear os detalhes do pedido

O programa atual preenche cada pedido de carro e imprime um resumo após a conclusão de cada pedido. Cada chamada para a função car_factory atende a um pedido retornando uma struct Car com os detalhes do pedido. O resultado é armazenado na variável car.

Como você já percebeu, o programa carece de algumas funcionalidades importantes. Não estamos acompanhando todos os pedidos. A variável car contém apenas os detalhes do pedido atual. Sempre que a variável car for atualizada com o resultado da função car_factory, os detalhes do pedido anterior serão substituídos.

Precisamos atualizar o programa para acompanhar todos os pedidos, como em um sistema de arquivamento. Para essa finalidade, vamos definir um mapa de hash com pares <K, V>. As chaves de mapa de hash corresponderão aos números de pedido de carro. Os valores do mapa de hash serão os detalhes do pedido para cada um conforme definido em um struct Car.

  1. Para definir o mapa de hash, adicione o seguinte código no início da função main, logo após a chave de abertura {:

        // Initialize a hash map for the car orders
        // - Key: Car order number, i32
        // - Value: Car order details, Car struct
        use std::collections::HashMap;
        let mut orders: HashMap<i32, Car> = HashMap;
    
  2. Corrija os problemas de sintaxe na instrução que cria o mapa de hash orders.

    Dica

    Você está criando um mapa de hash do zero, portanto, provavelmente deseja usar o método new().

  3. Compile o programa. Verifique se o código foi compilado antes de prosseguir para a próxima seção. Você pode ignorar mensagens de aviso do compilador.

Adicionar valores ao mapa de hash

A próxima etapa é adicionar cada pedido de carro atendido ao mapa de hash.

Na função main, chamamos a função car_factory para cada pedido de carro. Depois que o pedido for cumprido, chamamos a macro println! para mostrar os detalhes do pedido armazenados na variável car:

    // Car order #1: Used, Hard top
    car = car_factory(order, 1000);
    println!("{}: {}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);

    ...

    // Car order #6: Used, Hard top
    order = order + 1;
    car = car_factory(order, 4000);
    println!("{}: {}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);

Vamos revisar essas instruções de código para trabalhar com nosso novo mapa de hash:

  • Manteremos as chamadas para a função car_factory. Cada struct Car retornado será armazenado como parte do par <K, V> no mapa de hash.
  • Vamos atualizar as chamadas para a macro println! para mostrar os detalhes do pedido conforme eles são armazenados no mapa de hash.
  1. Na função main, localize as chamadas para a função car_factory e as chamadas que o acompanham para a macro println!:

        // Car order #1: Used, Hard top
        car = car_factory(order, 1000);
        println!("{}: {}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);
    
        ...
    
        // Car order #6: Used, Hard top
        order = order + 1;
        car = car_factory(order, 4000);
        println!("{}: {}, Hard top = {}, {:?}, {}, {} miles", order, car.age.0, car.roof, car.motor, car.color, car.age.1);
    
  2. Substitua o conjunto completo de instruções para todos os pedidos de carros pelo seguinte código revisado:

        // Car order #1: Used, Hard top
        car = car_factory(order, 1000);
        orders(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
        // Car order #2: Used, Convertible
        order = order + 1;
        car = car_factory(order, 2000);
        orders(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
        // Car order #3: New, Hard top
        order = order + 1;
        car = car_factory(order, 0);
        orders(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
        // Car order #4: New, Convertible
        order = order + 1;
        car = car_factory(order, 0);
        orders(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
        // Car order #5: Used, Hard top
        order = order + 1;
        car = car_factory(order, 3000);
        orders(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
        // Car order #6: Used, Hard top
        order = order + 1;
        car = car_factory(order, 4000);
        orders(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
  3. Se você tentar compilar seu programa agora, você verá erros de compilação. Há um problema de sintaxe nas instruções que adicionam os pares <K, V> ao mapa de hash orders. Você vê o problema? Vá em frente e corrija o problema em cada instrução que adiciona um pedido ao mapa de hash.

    Dica

    Não podemos atribuir valores diretamente ao mapa de hash orders. Precisamos usar um método para fazer as inserções.

Execute o programa

Depois que o programa for compilado com êxito, você verá a seguinte saída:

Car order 1: Some(Car { color: "Blue", motor: Manual, roof: true, age: ("Used", 1000) })
Car order 2: Some(Car { color: "Green", motor: SemiAuto, roof: false, age: ("Used", 2000) })
Car order 3: Some(Car { color: "Red", motor: Automatic, roof: true, age: ("New", 0) })
Car order 4: Some(Car { color: "Silver", motor: SemiAuto, roof: false, age: ("New", 0) })
Car order 5: Some(Car { color: "Blue", motor: Manual, roof: true, age: ("Used", 3000) })
Car order 6: Some(Car { color: "Green", motor: Automatic, roof: true, age: ("Used", 4000) })

Observe que a saída do código revisado é diferente. A macro println! exibe o conteúdo do struct Car mostrando cada valor e o nome do campo correspondente.

No próximo exercício, usaremos as expressões de loop para reduzir a redundância no código.

Solução

Você pode comparar a saída do programa à solução deste exercício neste Rust Playground.