类型驱动设计 m05-type-driven

类型驱动设计是一种利用编程语言的类型系统在编译时强制保证数据正确性和业务逻辑约束的软件开发方法。其核心思想是“使无效状态不可表示”,通过新类型模式、类型状态、幻影类型、标记特征、建造者模式等设计模式,将运行时可能出现的错误提前到编译时发现,从而提高代码的健壮性、安全性和可维护性。关键词:类型驱动设计、编译时验证、新类型模式、类型状态、Rust编程、软件架构、代码健壮性、防止无效状态。

架构设计 0 次安装 0 次浏览 更新于 2/27/2026

name: m05-type-driven description: “关键:用于类型驱动设计。触发词:类型状态、PhantomData、新类型模式、标记特征、建造者模式、使无效状态不可表示、编译时验证、密封特征、ZST、类型状态、新类型模式、类型驱动设计” user-invocable: false

类型驱动设计

层级 1:语言机制

核心问题

类型系统如何防止无效状态?

在诉诸运行时检查之前,请思考:

  • 编译器能捕获这个错误吗?
  • 能否使无效状态不可表示?
  • 类型能否编码这个不变量?

错误 → 设计问题

模式 不要只说 而是问
原始类型迷恋 “它只是一个字符串” 这个值代表什么?
布尔标志 “加一个 is_valid 标志” 状态能否成为类型?
到处使用 Optional “检查是否为 None” 缺失状态真的可能吗?
运行时验证 “无效则返回 Err” 我们能在构造时验证吗?

思考提示

在添加运行时验证之前:

  1. 类型能否编码约束?

    • 数值范围 → 有界类型或新类型
    • 有效状态 → 类型状态模式
    • 语义含义 → 新类型
  2. 何时可以进行验证?

    • 构造时 → 已验证的新类型
    • 状态转换时 → 类型状态
    • 仅在运行时 → 带有清晰错误的 Result
  3. 谁需要知道这个不变量?

    • 编译器 → 类型级编码
    • API 使用者 → 清晰的类型签名
    • 仅运行时 → 文档

向上追溯 ↑

当类型设计不清晰时:

"需要验证电子邮件格式"
    ↑ 问:这是一个领域值对象吗?
    ↑ 检查:m09-domain (Email 作为值对象)
    ↑ 检查:domain-* (验证要求)
情况 追溯至 问题
创建什么类型 m09-domain 领域模型是什么?
状态机设计 m09-domain 什么是有效转换?
标记特征用法 m04-zero-cost 静态还是动态分发?

向下追溯 ↓

从设计到实现:

"需要原始类型的类型安全包装"
    ↓ 新类型:struct UserId(u64);

"需要编译时状态验证"
    ↓ 类型状态:Connection<Connected>

"需要追踪幻影类型参数"
    ↓ PhantomData:PhantomData<T>

"需要能力标记"
    ↓ 标记特征:trait Validated {}

"需要渐进式构造"
    ↓ 建造者:Builder::new().field(x).build()

快速参考

模式 目的 示例
新类型 类型安全 struct UserId(u64);
类型状态 状态机 Connection<Connected>
PhantomData 变体/生命周期 PhantomData<&'a T>
标记特征 能力标志 trait Validated {}
建造者 渐进式构造 Builder::new().name("x").build()
密封特征 防止外部实现 mod private { pub trait Sealed {} }

模式示例

新类型

struct Email(String);  // 不只是任意字符串

impl Email {
    pub fn new(s: &str) -> Result<Self, ValidationError> {
        // 验证一次,永远信任
        validate_email(s)?;
        Ok(Self(s.to_string()))
    }
}

类型状态

struct Connection<State>(TcpStream, PhantomData<State>);

struct Disconnected;
struct Connected;
struct Authenticated;

impl Connection<Disconnected> {
    fn connect(self) -> Connection<Connected> { ... }
}

impl Connection<Connected> {
    fn authenticate(self) -> Connection<Authenticated> { ... }
}

决策指南

需求 模式
原始类型的类型安全 新类型
编译时状态验证 类型状态
生命周期/变体标记 PhantomData
能力标志 标记特征
渐进式构造 建造者
封闭的实现集合 密封特征
零大小类型标记 ZST 结构体

反模式

反模式 为何不好 更好的方案
用布尔标志表示状态 运行时错误 类型状态
用字符串表示语义类型 无类型安全 新类型
用 Option 表示未初始化 不变量不清晰 建造者
带有不变量的公共字段 不变量可能被破坏 私有字段 + 已验证的 new()

相关技能

何时 参见
领域建模 m09-domain
特征设计 m04-zero-cost
构造函数中的错误处理 m06-error-handling
反模式 m15-anti-pattern