Rust:Defining an Enum

Defining an Enum - The Rust Programming Language

構造体は関連するフィールドとデータをグループ化する1つの方法である。
列挙型(enum)は取りうる値のセットを定義する。

enum IpAddrKind {
    V4,
    V6,
}

Enumの値

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

enumには直接データを持たせることができ、さらに値ごとに異なるデータを関連付けることが可能

enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));

標準ライブラリのIpAddrは、それぞれの値に異なる構造体を持たせている。

enumには様々なデータをもたせることが可能である。

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
  • Qute:データなし
  • Move:構造体のような名前付きフィールド
  • Write:単一のString型
  • ChangeColor:3つの整数型

上記を構造体で表現した場合以下のようになるが、これらの全ての型に対応するような関数を定義することは簡単ではない。

struct QuitMessage; // unit struct
struct MoveMessage {
    x: i32,
    y: i32,
}
struct WriteMessage(String); // tuple struct
struct ChangeColorMessage(i32, i32, i32); // tuple struct

また、enumもメソッドを定義することができる。

impl Message {
    fn call(&self) {
        // method body would be defined here
    }
}

let m = Message::Write(String::from("hello"));
m.call();

Option型とNull値に対する優位性

Option型は標準ライブラリで定義されているenumで、何某かの値を持つか、何も無いかを一般化する。
Rustは他の多くの言語が持っているNullがなく、nullかnull以外かをOption<T>でコード化する。

enum Option<T> {
    None,
    Some(T),
}

Option<T>は通常のenumであり、Some(T)NoneOption<T>の取りうる値である。
<T>記法は、ジェネリック型引数で、今はSomeがあらゆる型のデータを1つ保持することができ、TマークはOption型全体として、実際の型に置き換わるとだけ理解しておけば良い。

    let some_number = Some(5);
    let some_char = Some('e');

    let absent_number: Option<i32> = None;
  • some_numberOption<i32>型で、some_charOption<char>型で異なる型になる。
  • RustはSomeに渡された実際の値で型を推測できるが、absent_numberは推測できないため、型を指定する必要がある
  • Someの場合は値があることを、Noneの場合は値がないことを表す。

何がnullよりよいのか?

Option<T>Tは異なる型になり、コンパイラOption<T>の値を確実に有効な値としては使用しない。

// i8とOption<i8>は異なる型のため、加算できないのでコンパイルエラーになる
 let x: i8 = 5;
 let y: Option<i8> = Some(5);
 let sum = x + y;

Rustではi8のような型の場合、コンパイラーが有効な値であることを保証してくれるため、nullチェックの必要がない。
Option<i8>のような型の場合のみ、値がない場合の考慮が必要で、そのようなケースをハンドリングしているかどうかをコンパイラーは確認する。

言い換えると、T型の処理をするには、Option<T>Tに変換する必要があり、その時、値がない場合のケースの処理も強制させるため、not nullエラーが発生しない。