연습: 루프를 사용하여 데이터 반복

완료됨

이 연습에서는 루프를 사용하여 자동차 주문을 반복하도록 자동차 공장 프로그램을 수정합니다.

전체 주문을 처리하는 루프 식을 추가하도록 main 함수를 업데이트합니다. 루프 구조는 코드의 중복성을 줄이는 데 도움이 됩니다. 코드를 간소화하여 주문 금액을 쉽게 늘릴 수 있습니다.

car_factory 함수에서 경계를 벗어난 값에 대한 런타임 패닉을 피하려면 다른 루프를 추가합니다.

도전 과제는 샘플 코드를 컴파일되고 실행하도록 완료하는 것입니다.

이 연습의 샘플 코드를 작업할 때 다음 두 가지 옵션이 있습니다.

  • 로컬 개발 환경에서 코드를 복사하고 편집합니다.
  • 준비된 Rust Playground에서 코드를 엽니다.

참고

샘플 코드에서 todo! 매크로를 찾습니다. 이 매크로는 완료하거나 업데이트해야 하는 코드를 나타냅니다.

프로그램 로드

마지막 연습에서 프로그램 코드를 닫은 경우 이 준비된 Rust Playground에서 코드를 다시 열 수 있습니다.

프로그램을 다시 빌드하고 컴파일러 오류 없이 실행되도록 해야 합니다.

루프 식을 통해 작업 반복

더 많은 주문을 지원하도록 프로그램을 업데이트해야 합니다. 현재 코드 구조는 중복 문을 사용하여 6개의 주문을 지원합니다. 중복성은 불편하고 유지 관리하기가 어렵습니다.

루프 식을 사용하여 각 순서를 만드는 작업을 반복하여 구조를 단순화할 수 있습니다. 간소화된 코드를 사용하면 많은 수의 주문을 빠르게 만들 수 있습니다.

  1. main 함수에서 다음 문을 제거합니다. 이 코드 블록은 order 변수를 정의 및 설정하고, 자동차 주문에 대한 car_factory 함수 및 println! 매크로를 호출하고, 각 주문을 orders 해시 맵에 삽입합니다.

        // Order 6 cars
        // - Increment "order" after each request
        // - Add each order <K, V> pair to "orders" hash map
        // - Call println! to show order details from the hash map
    
        // Initialize order variable
        let mut order = 1;
    
        // Car order #1: Used, Hard top
        car = car_factory(order, 1000);
        orders.insert(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
        ...
    
        // Car order #6: Used, Hard top
        order = order + 1;
        car = car_factory(order, 4000);
        orders.insert(order, car);
        println!("Car order {}: {:?}", order, orders.get(&order));
    
  2. 제거된 문을 다음 코드 블록으로 대체합니다.

        // Start with zero miles
        let mut miles = 0;
    
        todo!("Add a loop expression to fulfill orders for 6 cars, initialize `order` variable to 1") {
    
            // Call car_factory to fulfill order
            // Add order <K, V> pair to "orders" hash map
            // Call println! to show order details from the hash map        
            car = car_factory(order, miles);
            orders.insert(order, car);
            println!("Car order {}: {:?}", order, orders.get(&order));
    
            // Reset miles for order variety
            if miles == 2100 {
                miles = 0;
            } else {
                miles = miles + 700;
            }
        }
    
  3. 작업을 반복하여 6대의 자동차를 주문하는 루프 식을 추가합니다. 1로 초기화된 order 변수가 필요합니다.

  4. 프로그램을 빌드합니다. 코드가 오류 없이 컴파일되는지 확인합니다.

다음 예시와 유사한 출력이 표시됩니다.

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

자동차 주문을 11로 늘리기

이제 프로그램은 루프를 사용하여 6대의 자동차 주문을 처리합니다. 6대 이상의 자동차를 주문하면 어떻게 되나요?

  1. main 함수의 루프 식을 업데이트하여 11대의 자동차를 주문합니다.

        todo!("Update the loop expression to create 11 cars");
    
  2. 프로그램을 다시 빌드합니다. 런타임 중에 프로그램이 중단됩니다.

    Compiling playground v0.0.1 (/playground)
        Finished dev [unoptimized + debuginfo] target(s) in 1.26s
        Running `target/debug/playground`
    thread 'main' panicked at 'index out of bounds: the len is 4 but the index is 4', src/main.rs:34:29
    

이 문제를 해결 하는 방법을 살펴보겠습니다.

루프 식을 통해 런타임 패닉 방지

car_factory 함수에서 if/else 식을 사용하여 colors 배열의 color 인덱스 값을 확인합니다.

    // 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;
    }

colors 배열에는 4개의 요소가 있고 유효한 color 인덱스 범위는 0~3입니다. 조건식은 color 인덱스가 4보다 큰지 확인합니다. (color 인덱스가 4와 같은지는 확인하지 않습니다. 함수의 뒷부분에서 자동차 색을 할당하기 위해 배열에 인덱싱할 때 인덱스 값 color - 1에서 하나를 뺍니다. color 값 4는 배열에 colors[3]로 처리됩니다.)

현재 if/else 식은 8개 이하의 자동차를 주문할 때 런타임 패닉을 방지하기 위해 잘 작동합니다. 그러나 11대의 자동차를 주문하면 프로그램은 9번째 순서로 패닉 상태에 갑니다. 식을 더 강력하게 조정해야 합니다. 이를 개선하기 위해 다른 루프 식을 사용합니다.

  1. car_factory 함수에서 if/else 조건문을 루프 식으로 바꿉니다. color 색인 값이 4보다 큰 경우 런타임 패닉을 방지하려면 다음 의사 코드 문을 수정합니다.

        // Prevent panic: Check color index, reset as needed
        // If color = 1, 2, 3, or 4 - no change needed
        // If color > 4, reduce to color to a valid index
        let mut color = order as usize;
        todo!("Replace `if/else` condition with a loop to prevent run-time panic for color > 4");
    

    이 경우 if/else 조건을 루프 식으로 변경 하는 것은 실제로 매우 간단 합니다.

  2. 프로그램을 빌드합니다. 코드가 오류 없이 컴파일되는지 확인합니다.

다음 출력이 표시됩니다.

Car order 1: Some(Car { color: "Blue", motor: Manual, roof: true, age: ("New", 0) })
Car order 2: Some(Car { color: "Green", motor: SemiAuto, roof: false, age: ("Used", 700) })
Car order 3: Some(Car { color: "Red", motor: Automatic, roof: true, age: ("Used", 1400) })
Car order 4: Some(Car { color: "Silver", motor: SemiAuto, roof: false, age: ("Used", 2100) })
Car order 5: Some(Car { color: "Blue", motor: Manual, roof: true, age: ("New", 0) })
Car order 6: Some(Car { color: "Green", motor: Automatic, roof: true, age: ("Used", 700) })
Car order 7: Some(Car { color: "Red", motor: Manual, roof: true, age: ("Used", 1400) })
Car order 8: Some(Car { color: "Silver", motor: SemiAuto, roof: false, age: ("Used", 2100) })
Car order 9: Some(Car { color: "Blue", motor: Automatic, roof: true, age: ("New", 0) })
Car order 10: Some(Car { color: "Green", motor: SemiAuto, roof: false, age: ("Used", 700) })
Car order 11: Some(Car { color: "Red", motor: Manual, roof: true, age: ("Used", 1400) })

솔루션

Rust Playground에서 이 연습의 솔루션과 프로그램 출력을 비교할 수 있습니다.