mimikakimemo

自分用メモ。

Rust に付け焼き刃で入門する 5

Rust に付け焼き刃で入門する 4 の続き。

6. Enum とパターンマッチング

6.1. Enumを定義する

Enumを定義する - The Rust Programming Language 日本語版

enum IpAddrKind {
    V4,
    V6,
}

enum の定義。V4V6 を日本語ドキュメントでは列挙子と呼んでいるが、英語だと単純に variant。列挙子の名前は識別子として扱われているっぽいので、記号やスペースは含められないんだろうか? そもそも、Rust の識別子に使える文字種がどうなっているのか、まだ知らないが。

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

列挙子のインスタンスを生成する。IpAddrKind::V4IpAddrKind::V6 は値。その両方を含んだ型が IpAddrKind

:: を使っているのは、関連関数の :: と関係あるんだろうか?

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

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

このようにして、列挙子に具体的なデータを格納することができる。列挙型はユニオン型のようになる。

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

Move は匿名構造体をデータとして持つ列挙子。匿名構造体ってのは初めて出てきた気がする。他の箇所でも使えるんだろうか。

enumと構造体にはもう1点似通っているところがあります: implを使って構造体にメソッドを定義できるのと全く同様に、 enumにもメソッドを定義することができるのです。

なるほど。関連関数は定義できるんだろうか?と思って試してみたらいけた。

#[derive(Debug)]
enum Hoge {
    Foo(i32),
    Bar(bool),
}

impl Hoge {
    fn print(&self) {
        println!("{:?}", self);
    }
    // 関連関数を定義
    fn make_bar(value: bool) -> Hoge {
        Hoge::Bar(value)
    }
}

fn main() {
    let foo = Hoge::Foo(123);
    let bar = Hoge::make_bar(true); // 関連関数を呼び出す
    foo.print(); // → Foo(123)
    bar.print(); // → Bar(true)
}

Rustにはnullがありませんが、 値が存在するか不在かという概念をコード化するenumならあります。このenumOption<T>で、 以下のように標準ライブラリに定義されています。

Haskell でいう Maybe 的なやつ。

Option<T>は有益すぎて、初期化処理(prelude)にさえ含まれています。つまり、明示的にスコープに導入する必要がないのです。 さらに、列挙子もそうなっています: SomeNoneOption::の接頭辞なしに直接使えるわけです。

しれっと使われている SomeNone は、Option::SomeOption::Noneenum だったのか。

では、Option<T>型の値がある時、その値を使えるようにするには、どのようにSome列挙子からT型の値を取り出せばいいのでしょうか? Option<T>には様々な場面で有効に活用できる非常に多くのメソッドが用意されています; ドキュメントでそれらを確認できます。

Some(42) から値 42 を取り出す方法は、この節では濁されている。ドキュメントを見てみると、unwrap() メソッドでできるようだ。

6.2. matchフロー制御演算子

matchフロー制御演算子 - The Rust Programming Language 日本語版

パターンマッチ。説明されていないが、各アームが返す型はすべて同じでなければならないようだ。

Rustにおけるマッチは、包括的です: 全てのあらゆる可能性を網羅し尽くさなければ、コードは有効にならないのです。

これも Haskell など他の言語と同様。また、ワイルドカード的なプレースホルダとして、パターン中に _ が使える。

6.3. if letで簡潔なフロー制御

if letで簡潔なフロー制御 - The Rust Programming Language 日本語版

let some_u8_value = Some(0u8);

match some_u8_value {
    Some(3) => println!("three"),
    _ => (),
}

let some_u8_value = Some(0u8);

if let Some(3) = some_u8_value {
    println!("three");
}

は等価。if let と書かれていたので一瞬構造がよくわからなかったが、「普通の if 式の条件の部分に let Some(3) = some_u8_value が入っている」と見ればよさそう。変数定義に使う let と被っているのも紛らわしいが、パターンマッチのための「let <pattern> = <valiable>」という特別な構文、という理解でいいんだろうか。


enum とパターンマッチ。若干独特な部分はあるが、変な概念はない。