Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Typestateプログラミング

typestates の概念では、オブジェクトの現在の状態に関する情報を、そのオブジェクトの型にエンコードします。これは少し難解に聞こえるかもしれませんが、Rust で Builder Pattern を使ったことがあるなら、すでに Typestateプログラミングを使い始めています!

pub mod foo_module {
    #[derive(Debug)]
    pub struct Foo {
        inner: u32,
    }

    pub struct FooBuilder {
        a: u32,
        b: u32,
    }

    impl FooBuilder {
        pub fn new(starter: u32) -> Self {
            Self {
                a: starter,
                b: starter,
            }
        }

        pub fn double_a(self) -> Self {
            Self {
                a: self.a * 2,
                b: self.b,
            }
        }

        pub fn into_foo(self) -> Foo {
            Foo {
                inner: self.a + self.b,
            }
        }
    }
}

fn main() {
    let x = foo_module::FooBuilder::new(10)
        .double_a()
        .into_foo();

    println!("{:#?}", x);
}

この例では、Foo オブジェクトを直接作成する方法はありません。必要な Foo オブジェクトを得るには、まず FooBuilder を作成し、それを適切に初期化する必要があります。

この最小限の例では、2 つの状態がエンコードされています。

  • FooBuilder は、「未設定」または「設定中」の状態を表します
  • Foo は、「設定済み」または「使用可能」な状態を表します

強い型

Rust には Strong Type System があるため、Foo のインスタンスを魔法のように簡単に作成したり、into_foo() メソッドを呼ばずに FooBuilderFoo に変えたりする簡単な方法はありません。さらに、into_foo() メソッドを呼び出すと元の FooBuilder 構造体は消費されるため、新しいインスタンスを作成しない限り再利用できません。

これにより、システムの状態を型として表現し、ある型を別の型に交換するメソッドに、状態遷移に必要な操作を組み込めます。FooBuilder を作成し、それを Foo オブジェクトに交換することで、基本的な状態機械のステップをたどったことになります。