Паттерн typestate с обобщениями
Комбинируя моделирование typestate с обобщениями, мы можем выразить более широкий набор допустимых состояний и переходов, не дублируя логику. Этот подход особенно полезен, когда количество состояний растёт или когда несколько состояний имеют общее поведение, но различаются по структуре.
// Copyright 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 допускает только корректные переходы, как показано на следующей схеме:
-
Используя обобщения для отслеживания родительского контекста, мы можем построить сериализаторы с произвольной вложенностью, которые обеспечивают корректные переходы между состояниями структуры, списка и свойства.
-
Это позволяет построить рекурсивную структуру, сохраняя строгий контроль над тем, какие методы доступны в каждом состоянии.
-
Методы, общие для всех состояний, можно определить для любого
SвSerializer<S>. -
Маркерные типы (например,
List<S>) не создают накладных расходов ни по памяти, ни во время выполнения, так как не содержат данных, кроме возможного типа нулевого размера (Zero-Sized Type). Их единственная роль — обеспечивать корректное использование API с помощью системы типов.