直接回答:typestate 模式把对象的状态编码成类型参数:同一逻辑实体在不同状态下是不同的类型(如 Connection、Connection),每个状态只暴露该状态下合法的方法,状态转移方法消费 self 并返回新状态的类型。于是“未连接就发送数据”“重复关闭”这类错误在编译期就是类型错误,根本编译不过。

展开解析:经典例子是 builder 与协议状态机:HttpRequest 只有 url() 方法,调用后变成 HttpRequest 才出现 send()。实现手法:用零大小类型(ZST)当状态标记,配合泛型参数的 impl 块按状态分别实现方法;转移方法签名 fn connect(self) -> Connection,消费旧值防止旧状态被复用。收益:消灭一整类运行时状态检查与非法状态错误分支,API 自我文档化,IDE 补全只列出当前合法操作。代价:类型签名变复杂,错误信息对使用者不友好;状态组合爆炸时类型数量膨胀;同一个变量在不同分支处于不同状态时控制流难写(if 分支里转移状态后类型分裂,常需枚举降级回运行时检查)。实践建议是状态少、非法流转代价高(安全协议、硬件驱动、事务)时用 typestate,状态多或动态时回到枚举 + 运行时校验,别为用而用。

追问方向:与枚举表示状态相比各适合什么场景?如何与 async 结合?

(约 470 字)