演習: ハッシュ マップを使用して注文を追跡する
この演習では、ハッシュ マップを使用するために自動車工場プログラムを変更します。
ハッシュ マップ キーと値のペアを使用して、自動車の注文に関する詳細を追跡し、出力を表示します。 ここでも、課題は、コンパイルして実行できるようにサンプル コードを完成させることです。
この演習用のサンプル コードを操作するには、次の 2 つの方法があります。
- コードをコピーし、ローカルの開発環境で編集します。
- 準備済みの Rust Playground 内でコードを開きます。
注意
サンプル コードで、todo!
マクロを探します。 このマクロは、完了または更新する必要があるコードを示しています。
現在のプログラムを読み込む
最初の手順では、既存のプログラム コードを取得します。
編集する既存のプログラム コードを開きます。 このコードには、データ型の宣言と、
car_quality
、car_factory
、およびmain
関数の定義が含まれています。次のコードをコピーし、ローカルの開発環境で編集します。
または、この準備済みの Rust Playground 内でコードを開きます。#[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); }
プログラムをビルドします。 次のセクションに進む前に、コードがコンパイルされ、実行されることを確認してください。
次の出力が表示されます。
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
注文の詳細を追跡するハッシュ マップを追加する
現在のプログラムでは、各自動車の注文が満たされ、各注文の完了後に概要が出力されます。 car_factory
関数を呼び出すたびに、注文の詳細を含む Car
構造体が返されて注文が満たされます。 結果は car
変数に格納されます。
お気付きかもしれませんが、プログラムにはいくつかの重要な機能がありません。 すべての注文を追跡しているわけではありません。 car
変数には、現在の注文の詳細のみが保持されます。 car_factory
関数からの結果で car
変数が更新されるたびに、前の注文の詳細が上書きされます。
ファイリング システムの場合のようにすべての注文を追跡するには、プログラムを更新する必要があります。 このために、<K、V> ペアでハッシュ マップを定義します。 ハッシュ マップ キーは自動車の注文番号に対応します。 ハッシュ マップ値は、Car
構造体で定義されているそれぞれの注文の詳細となります。
ハッシュ マップを定義するには、
main
関数の先頭の左中かっこ{
の直後に次のコードを追加します。// 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;
orders
ハッシュ マップを作成するステートメントの構文の問題を修正します。ヒント
ハッシュ マップを最初から作成しているので、おそらく
new()
メソッドを使用します。プログラムをビルドします。 次のセクションに進む前に、コードがコンパイルされることを確認してください。 コンパイラからの警告メッセージは無視してかまいません。
ハッシュ マップに値を追加する
次の手順では、ハッシュ マップに自動車の満たされた各注文を追加します。
main
関数では、自動車の各注文に対して car_factory
関数を呼び出します。 注文が満たされた後、println!
マクロを呼び出して、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);
新しいハッシュ マップを操作するために、これらのコード ステートメントを修正します。
car_factory
関数の呼び出しを保持する。 返された各Car
構造体は、ハッシュ マップに <K、V> ペアの一部として格納されます。println!
マクロの呼び出しを更新して、ハッシュ マップに格納されている注文の詳細を表示する。
main
関数で、car_factory
関数の呼び出しと、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);
すべての自動車注文のステートメントの完全なセットを、次の修正後のコードに置き換えます。
// 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));
ここでプログラムをビルドしようとすると、コンパイル エラーが表示されます。 <K、V> ペアを
orders
ハッシュ マップに追加するステートメントには、構文の問題があります。 その問題がわかりますか。 それでは、注文をハッシュ マップに追加する各ステートメントの問題を修正しましょう。ヒント
orders
ハッシュ マップに値を直接割り当てることはできません。 挿入を行うには、メソッドを使用する必要があります。
プログラムの実行
プログラムが正常にビルドされた後、次の出力が表示されるはずです。
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) })
変更後のコードの出力が異なることに注目してください。 println!
マクロでは、各値と対応するフィールド名を表示することによって、Car
構造体の内容を表示します。
次の演習では、ループ式を使用してコード内の冗長性を減らします。
解決策
この Rust Playground 内で、プログラム出力をこの演習のソリューションと比較できます。