演習: 複合型を処理する

完了

この演習では、複合データ型を使用して、自動車工場プログラムを拡張します。

タプルを使用して、関連するがデータ型が異なる 2 つの値を使用して自動車の品質を追跡します。 このタプルをこの関数の呼び出し元に返す car_quality という名前の関数を作成します。 main 関数で、car_factory 関数を呼び出して各自動車注文を作成します。

課題は、コンパイルして実できるようにサンプル コードを完成させることです。

この演習用のサンプル コードを操作するには、次の 2 つの方法があります。

  • コードをコピーし、ローカルの開発環境で編集します。
  • 準備済みの Rust Playground 内でコードを開きます。

注意

サンプル コードで、todo! マクロを探します。 このマクロは、完了または更新する必要があるコードを示しています。

タプル フィールドを持つように Car 構造体を更新する

最初のタスクは、Car 構造体の定義の変更です。 mileage フィールドを age という名前のタプル フィールドに移動します。 走行距離値と共に、age タプルには、自動車が "新車" か "中古" かを識別するための別のフィールドが必要です。

  1. サンプル コードの最初のブロックを開きます。

    次のコードをコピーしてローカルの開発環境で編集するか、この用意されている Rust プレイグラウンドでコードを開きます。

    #[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. 自動車の品質を記述するために、"新車" と "中古" の値を持つ Age という名前の列挙型を追加します。

  3. Car 構造体の宣言を修正します。

    1. mileage: u32 フィールドを age という名前のタプル フィールドに置き換えます。
    2. Age 列挙値と自動車走行距離の 2 つのフィールドを持つ age タプルを定義します。
  4. プログラムをビルドします。 次のセクションに進む前に、コードがコンパイルされることを確認してください。

    コードではまだ出力は表示されませんが、エラーなしでコンパイルされる必要があります。 コンパイラからの "警告" メッセージは無視してかまいません。 警告は、列挙型と構造体の定義を宣言したものの、これらをまだ使用していないことが原因で生成されます。

car_quality 関数を作成する

次に、car_quality という名前の新しい関数のコードを追加します。 この関数は、自動車走行距離を入力引数として受け取ります。 走行距離と自動車年数を保持するタプルを作成します。 関数から呼び出し元にタプルが返されます。

  1. 既存のコードに次のコード ブロックを追加します。 新しいコードは、ファイルの先頭または末尾に追加できます。

    // 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. "新車" の quality タプル値を設定するコードを完成させます。

  3. 関数の末尾にある return ステートメントを更新して、完成したタプルを呼び出し元に返します。

  4. プログラムをビルドします。 次のセクションに進む前に、コードがコンパイルされることを確認してください。 コードではまだ出力は表示されませんが、エラーなしでコンパイルされる必要があります。

car_factory 関数を更新する

次の手順では、car_factory 関数を更新します。 car_quality 関数から返されるタプルをサポートする必要があります。 Car 構造体の定義を更新したので、データを正しく処理するように関数本体を調整する必要があります。

  1. 既存のコードに次のコード ブロックを追加します。 新しいコードは、ファイルの先頭または末尾に追加できます。

    // 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. car 変数の初期化を修正します。

    1. mileage: miles フィールドを age という名前のタプル フィールドに置き換えます。
    2. age フィールドは、car_quality 関数を miles 入力引数を使用して呼び出す必要があります。
  3. プログラムをビルドします。 次のセクションに進む前に、コードがコンパイルされることを確認してください。

main 関数の変数を設定する

これで、main 関数の操作を開始する準備ができました。 最初の手順で、プログラムで使用する変数を定義します。

  • 自動車の色の配列
  • 各自動車注文の構造体
  • トランスミッションの種類を記述する列挙型
  1. main 関数の次のコード ブロックを既存のコードに追加します。 新しいコードは、ファイルの先頭または末尾に追加できます。

    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. colors 配列変数の定義を完了します。 自動車は、青、緑、赤、シルバーの 4 色のいずれかにすることができます。

  3. car 構造体および engine 列挙型変数の宣言構文を修正します。 engine 列挙型を "Manual" に初期化します。

    ヒント

    両方の変数を変更可能として作成することを忘れないでください。

  4. プログラムをビルドします。 次のセクションに進む前に、コードがエラーなしでコンパイルされることを確認してください。

自動車注文を遂行する関数を呼び出す

main 関数で、自動車注文を遂行する car_factory 関数を呼び出します。 関数呼び出しでは、自動車の色が必要です。 colors 配列にインデックスを付ける方法を修正して、実際に期待された色を渡すようにする必要があります。

  1. main 関数に次のコード ブロックを追加します。 このコードは、前の手順で追加した定義の後、かつ関数の右中かっこ } の前に配置します。

        // 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. String::from の呼び出しで colors 配列のインデックス付けを修正します。 colors 配列には 4 つの要素があるため、注文ごとに異なる色を使用するように試行します。

    ヒント

    配列内の要素は、インデックス位置 0 から開始します。 最初の要素の値はインデックス位置 0 にあります。

  3. プログラムをビルドします。 コードがエラーなしでコンパイルされることを確認します。 警告メッセージはすべて無視してかまいません。

プログラムの実行

プログラムが完了すると、この例のような出力が表示されます。

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

注文 2 と 3 は中古車用ですが、car_quality 関数からは現在のところ New のみが返されます。 後の演習で、条件式を使用してそれを修正し、注文を変更する方法について確認します。

解決策

この Rust Playground 内で、プログラム出力をこの演習のソリューションと比較できます。