テストケース: 連結リスト

enumを使用が適切なパターンのひとつに、連結リスト(linked-list)を作成する場合があります。

use crate::List::*;

enum List {
    // Cons: Tuple struct that wraps an element and a pointer to the next node
    // Cons: これは、要素をラップし、次の要素へのポインタを保持するタプル。
    Cons(u32, Box<List>),
    // Nil: A node that signifies the end of the linked list
    // Nil: 連結リストの終端であることを示すノード
    Nil,
}

// Methods can be attached to an enum
// 列挙型にはメソッドを付与することができる。
impl List {
    // Create an empty list
    // 空リストの作成。
    fn new() -> List {
        // `Nil` has type `List`
        // `Nil` は `List`型を持つ。
        Nil
    }

    // Consume a list, and return the same list with a new element at its front
    // リストを受け取り、その始端に新しい要素を付加したものを返す関数。
    fn prepend(self, elem: u32) -> List {
        // `Cons` also has type List
        // この`Cons` 自体も、その第2要素もどちらもlist型である。
        Cons(elem, Box::new(self))
    }

    // Return the length of the list
    // list の長さを返すメソッド
    fn len(&self) -> u32 {
        // `self` has to be matched, because the behavior of this method
        // depends on the variant of `self`
        // `self` has type `&List`, and `*self` has type `List`, matching on a
        // concrete type `T` is preferred over a match on a reference `&T`
        // after Rust 2018 you can use self here and tail (with no ref) below as well,
        // rust will infer &s and ref tail. 
        // See https://doc.rust-lang.org/edition-guide/rust-2018/ownership-and-lifetimes/default-match-bindings.html
        // このメソッドは、`self`の状態によって振る舞いが
        // 変化するため、matchをする必要がある。
        // `self`の型は`&List`であるので、`*self`は`List`になる。マッチングは
        // リファレンス(`&T`)ではなく実体(`T`)に対して行うのが好ましい。
        match *self {
            // Can't take ownership of the tail, because `self` is borrowed;
            // instead take a reference to the tail
            // `self`をすでに借用しているので、tailの所有権を取ることができない。
            // 代わりに参照を使用する。
            Cons(_, ref tail) => 1 + tail.len(),
            // Base Case: An empty list has zero length
            // 空リストならば長さは0
            Nil => 0
        }
    }

    // Return representation of the list as a (heap allocated) string
    // Listをheap上の文字列として表したものを返すメソッド。
    fn stringify(&self) -> String {
        match *self {
            Cons(head, ref tail) => {
                // `format!` is similar to `print!`, but returns a heap
                // allocated string instead of printing to the console
                // `format!`は`print!`に似ているが、コンソール上に出力
                // する代わりに、heap上の文字列を返す。
                format!("{}, {}", head, tail.stringify())
            },
            Nil => {
                format!("Nil")
            },
        }
    }
}

fn main() {
    // Create an empty linked list
    // 空の連結リストを作成
    let mut list = List::new();

    // Prepend some elements
    // 要素を追加
    list = list.prepend(1);
    list = list.prepend(2);
    list = list.prepend(3);

    // Show the final state of the list
    // 追加後の状態を表示
    println!("linked list has length: {}", list.len());
    println!("{}", list.stringify());
}

参照

ボックス(Box), メソッド

関連キーワード:  list, self, List, テストケース, tail, 関数, Nil, メソッド, Cons, Result