ジェネリクスを使った Typestate パターン

typestate モデリングをジェネリクスと組み合わせることで、ロジックを重複させることなく、より幅広い有効な状態と遷移を表現できます。このアプローチは、状態数が増える場合や、複数の状態が振る舞いを共有しつつ構造が異なる場合に特に有用です。

// 著作権 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

struct Serializer<S> {
    // [...]
    indent: usize,
    buffer: String,
    state: S,
}

struct Root;
struct Struct<S>(S);
struct Property<S>(S);
struct List<S>(S);

これで、Serializer とその状態型定義のメソッドを実装するために必要な要素がすべてそろいました。これにより、次の図に示すように、API は有効な遷移のみを許可するようになります。

  • 親コンテキストを追跡するためにジェネリクスを活用することで、struct、list、property の各状態間で有効な遷移を強制する、任意の深さにネストしたシリアライザーを構築できます。

  • これにより、再帰的な構造を構築しつつ、各状態でどのメソッドにアクセスできるかを厳密に制御できます。

  • すべての状態に共通するメソッドは、Serializer<S> における任意の S に対して定義できます。

  • マーカー型(例: List<S>)は、ゼロサイズ型である可能性のあるデータ以外を含まないため、メモリや実行時のオーバーヘッドを生じません。その唯一の役割は、型システムを通じて正しい API の使い方を強制することです。