複合データに列挙型バリアントを使用する

完了

列挙型は、複数のバリアントのいずれも指定できる型です。 Rust で列挙型と呼ぶものは、より一般的には代数的データ型として知られています。 重要な詳細は、各列挙型バリアントには、それに付随するデータを指定できることです。

列挙型の作成には enum キーワードを使用します。これには、列挙型バリアントを任意に組み合わせることができます。 列挙型バリアントは、構造体と同様に、名前があるフィールドを持つことが可能です。しかし、名前がないフィールドを持つことも、まったくフィールドを持たないことも可能です。 構造体型と同様に、列挙型も大文字になります。

列挙型の定義

次の例では、Web イベントを分類する列挙型を定義します。 列挙型内の各バリアントは独立しており、さまざまな量と型の値を格納します。

enum WebEvent {
    // An enum variant can be like a unit struct without fields or data types
    WELoad,
    // An enum variant can be like a tuple struct with data types but no named fields
    WEKeys(String, char),
    // An enum variant can be like a classic struct with named fields and their data types
    WEClick { x: i64, y: i64 }
}

この例の列挙型には、型が異なる 3 つのバリアントがあります。

  • WELoad には、データ型またはデータが関連付けられていません。
  • WEKeys には、データ型が String および char である 2 つのフィールドがあります。
  • WEMClick には、名前付きフィールド xy、およびそれらのデータ型 (i64) を持つ匿名構造体が含まれています。

さまざまな種類の構造体型を定義するのと同様の方法で、バリアントのある列挙型を定義します。 すべてのバリアントは、同じ WebEvent 列挙型でグループ化されます。 列挙型の各バリアントは、独自の型ではありませんWebEvent 列挙型のバリアントを使用する関数はすべて、列挙型内のすべてのバリアントを受け入れる必要があります。 WEClick バリアントだけを受け入れ、他のバリアントは受け入れない関数を使用することはできません。

構造体を使用して列挙型を定義する

列挙型のバリアント要件を回避する方法は、列挙型のバリアントごとに個別の構造体を定義することです。 次に、列挙型の各バリアントでは、対応する構造体が使用されます。 構造体には、対応する列挙型バリアントによって保持されていたものと同じデータが保持されます。 この定義スタイルにより、それぞれの論理バリアントを単独で参照できるようになります。

次のコードは、この代替定義スタイルを使用する方法を示しています。 構造体は、データを保持するように定義されています。 列挙型のバリアントは、構造体を参照するように定義されています。

// Define a tuple struct
struct KeyPress(String, char);

// Define a classic struct
struct MouseClick { x: i64, y: i64 }

// Redefine the enum variants to use the data from the new structs
// Update the page Load variant to have the boolean type
enum WebEvent { WELoad(bool), WEClick(MouseClick), WEKeys(KeyPress) }

列挙型をインスタンス化する

次に、列挙型バリアントのインスタンスを作成するコードを追加しましょう。 バリアントごとに、let キーワードを使用して代入を行います。 列挙型の定義で特定のバリアントにアクセスするには、二重コロン :: を含む構文 <enum>::<variant> を使用します。

単純なバリアント: WELoad(bool)

WebEvent 列挙型の最初のバリアントには、WELoad(bool) という 1 つのブール値があります。 このバリアントは、前のユニットでブール値を操作した場合と同様の方法でインスタンス化します。

let we_load = WebEvent::WELoad(true);

構造体バリアント: WEClick(MouseClick)

2 番目のバリアントには、従来の構造体 WEClick(MouseClick) が含まれています。 構造体には x および y という 2 つの名前付きフィールドがあり、両方のフィールドに i64 データ型があります。 このバリアントを作成するには、まず構造体をインスタンス化します。 次に、バリアントをインスタンス化するための呼び出しで、構造体を引数として渡します。

// Instantiate a MouseClick struct and bind the coordinate values
let click = MouseClick { x: 100, y: 250 };

// Set the WEClick variant to use the data in the click struct
let we_click = WebEvent::WEClick(click);

タプル バリアント: WEKeys(KeyPress)

最後のバリアントにはタプル WEKeys(KeyPress) が含まれています。 タプルには、String および char データ型を使用する 2 つのフィールドがあります。 このバリアントを作成するには、まずタプルをインスタンス化します。 次に、バリアントをインスタンス化するための呼び出しで、タプルを引数として渡します。

// Instantiate a KeyPress tuple and bind the key values
let keys = KeyPress(String::from("Ctrl+"), 'N');
    
// Set the WEKeys variant to use the data in the keys tuple
let we_key = WebEvent::WEKeys(keys);

このコードでは、String::from("<value>") 構文を使用していることに注意してください。 この構文では、Rust の from メソッドを呼び出すことによって型 String の値が作成されます。 メソッドには、二重引用符で囲まれたデータの入力引数が必要です。

列挙型の例

列挙型バリアントをインスタンス化するための最終的なコードは次のようになります。

// Define a tuple struct
#[derive(Debug)]
struct KeyPress(String, char);

// Define a classic struct
#[derive(Debug)]
struct MouseClick { x: i64, y: i64 }

// Define the WebEvent enum variants to use the data from the structs
// and a boolean type for the page Load variant
#[derive(Debug)]
enum WebEvent { WELoad(bool), WEClick(MouseClick), WEKeys(KeyPress) }

fn main() {
    // Instantiate a MouseClick struct and bind the coordinate values
    let click = MouseClick { x: 100, y: 250 };
    println!("Mouse click location: {}, {}", click.x, click.y);
        
    // Instantiate a KeyPress tuple and bind the key values
    let keys = KeyPress(String::from("Ctrl+"), 'N');
    println!("\nKeys pressed: {}{}", keys.0, keys.1);
        
    // Instantiate WebEvent enum variants
    // Set the boolean page Load value to true
    let we_load = WebEvent::WELoad(true);
    // Set the WEClick variant to use the data in the click struct
    let we_click = WebEvent::WEClick(click);
    // Set the WEKeys variant to use the data in the keys tuple
    let we_key = WebEvent::WEKeys(keys);
        
    // Print the values in the WebEvent enum variants
    // Use the {:#?} syntax to display the enum structure and data in a readable form
    println!("\nWebEvent enum structure: \n\n {:#?} \n\n {:#?} \n\n {:#?}", we_load, we_click, we_key);
}

Rust Playground 内で、このコード例を操作してみてください。

デバッグ ステートメント

前の例で、次のコード ステートメントを探します。 このステートメントは、コード内のいくつかの場所で使用されています。

// Set the Debug flag so we can check the data in the output
#[derive(Debug)]

#[derive(Debug)] 構文を使用すると、コードの実行中に、標準出力では見ることのできない特定の値を確認できます。 println! マクロでデバッグ データを表示するには、構文 {:#?} を使用して、読み取り可能な方法でデータを書式設定します。

自分の知識をチェックする

次の質問に答えて、学習した内容を確認してください。 質問ごとに回答を 1 つ選択して、[回答を確認] を選択します。

1.

Rust の列挙型のすべてのバリアントは、同じ型にグループ化されます。 列挙型のいずれかのバリアントを使う関数では、そのすべてのバリアントを受け入れる必要があります。 列挙型バリアントのこれらの要件を回避するにはどうすればよいですか?