m05-type-driven
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseType-Driven Design
Type-Driven Design
Layer 1: Language Mechanics
第一层:语言机制
Core Question
核心问题
How can the type system prevent invalid states?
Before reaching for runtime checks:
- Can the compiler catch this error?
- Can invalid states be unrepresentable?
- Can the type encode the invariant?
类型系统如何防止无效状态?
在使用运行时检查之前:
- 编译器能否捕获这个错误?
- 能否让无效状态无法被表示?
- 类型能否编码不变式?
Error → Design Question
错误→设计问题
| Pattern | Don't Just Say | Ask Instead |
|---|---|---|
| Primitive obsession | "It's just a string" | What does this value represent? |
| Boolean flags | "Add an is_valid flag" | Can states be types? |
| Optional everywhere | "Check for None" | Is absence really possible? |
| Validation at runtime | "Return Err if invalid" | Can we validate at construction? |
| 模式 | 不要只说 | 换个问法 |
|---|---|---|
| 原始类型滥用 | "这只是个字符串" | 这个值代表什么? |
| 布尔标志过度使用 | "加个is_valid标志" | 能否将状态设计为类型? |
| 到处使用可选类型 | "检查是否为None" | 真的可能存在缺失的情况吗? |
| 运行时验证 | "无效时返回Err" | 能否在构造时就完成验证? |
Thinking Prompt
思考提示
Before adding runtime validation:
-
Can the type encode the constraint?
- Numeric range → bounded types or newtypes
- Valid states → type state pattern
- Semantic meaning → newtype
-
When is validation possible?
- At construction → validated newtype
- At state transition → type state
- Only at runtime → Result with clear error
-
Who needs to know the invariant?
- Compiler → type-level encoding
- API users → clear type signatures
- Runtime only → documentation
在添加运行时验证之前:
-
类型能否编码约束?
- 数值范围 → 有界类型或newtype
- 有效状态 → type state模式
- 语义含义 → newtype
-
何时可以进行验证?
- 构造时 → 已验证的newtype
- 状态转换时 → type state
- 仅能在运行时 → 返回带有明确错误的Result
-
谁需要了解这个不变式?
- 编译器 → 类型层面的编码
- API使用者 → 清晰的类型签名
- 仅运行时需要 → 文档说明
Trace Up ↑
向上追溯 ↑
When type design is unclear:
"Need to validate email format"
↑ Ask: Is this a domain value object?
↑ Check: m09-domain (Email as Value Object)
↑ Check: domain-* (validation requirements)| Situation | Trace To | Question |
|---|---|---|
| What types to create | m09-domain | What's the domain model? |
| State machine design | m09-domain | What are valid transitions? |
| Marker trait usage | m04-zero-cost | Static or dynamic dispatch? |
当类型设计不明确时:
"需要验证邮箱格式"
↑ 提问:这是领域值对象吗?
↑ 查看:m09-domain(邮箱作为值对象)
↑ 查看:domain-*(验证要求)| 场景 | 追溯至 | 问题 |
|---|---|---|
| 需要创建哪些类型 | m09-domain | 领域模型是什么? |
| 状态机设计 | m09-domain | 有效的状态转换有哪些? |
| Marker trait的使用 | m04-zero-cost | 使用静态还是动态分发? |
Trace Down ↓
向下落地 ↓
From design to implementation:
"Need type-safe wrapper for primitives"
↓ Newtype: struct UserId(u64);
"Need compile-time state validation"
↓ Type State: Connection<Connected>
"Need to track phantom type parameters"
↓ PhantomData: PhantomData<T>
"Need capability markers"
↓ Marker Trait: trait Validated {}
"Need gradual construction"
↓ Builder: Builder::new().field(x).build()从设计到实现:
"需要为原始类型提供类型安全的包装器"
↓ Newtype: struct UserId(u64);
"需要编译时状态验证"
↓ Type State: Connection<Connected>
"需要跟踪幽灵类型参数"
↓ PhantomData: PhantomData<T>
"需要能力标记"
↓ Marker Trait: trait Validated {}
"需要逐步构建"
↓ Builder: Builder::new().field(x).build()Quick Reference
快速参考
| Pattern | Purpose | Example |
|---|---|---|
| Newtype | Type safety | |
| Type State | State machine | |
| PhantomData | Variance/lifetime | |
| Marker Trait | Capability flag | |
| Builder | Gradual construction | |
| Sealed Trait | Prevent external impl | |
| 模式 | 用途 | 示例 |
|---|---|---|
| Newtype | 类型安全 | |
| Type State | 状态机 | |
| PhantomData | 可变性/生命周期跟踪 | |
| Marker Trait | 能力标记 | |
| Builder | 逐步构建 | |
| Sealed Trait | 防止外部实现 | |
Pattern Examples
模式示例
Newtype
Newtype模式
rust
struct Email(String); // Not just any string
impl Email {
pub fn new(s: &str) -> Result<Self, ValidationError> {
// Validate once, trust forever
validate_email(s)?;
Ok(Self(s.to_string()))
}
}rust
struct Email(String); // 不只是普通字符串
impl Email {
pub fn new(s: &str) -> Result<Self, ValidationError> {
// 验证一次,永久信任
validate_email(s)?;
Ok(Self(s.to_string()))
}
}Type State
Type State模式
rust
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> { ... }
}rust
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> { ... }
}Decision Guide
决策指南
| Need | Pattern |
|---|---|
| Type safety for primitives | Newtype |
| Compile-time state validation | Type State |
| Lifetime/variance markers | PhantomData |
| Capability flags | Marker Trait |
| Gradual construction | Builder |
| Closed set of impls | Sealed Trait |
| Zero-sized type marker | ZST struct |
| 需求 | 模式 |
|---|---|
| 原始类型的类型安全 | Newtype |
| 编译时状态验证 | Type State |
| 生命周期/可变性标记 | PhantomData |
| 能力标志 | Marker Trait |
| 逐步构建 | Builder |
| 封闭的实现集合 | Sealed Trait |
| 零大小类型标记 | ZST struct |
Anti-Patterns
反模式
| Anti-Pattern | Why Bad | Better |
|---|---|---|
| Boolean flags for states | Runtime errors | Type state |
| String for semantic types | No type safety | Newtype |
| Option for uninitialized | Unclear invariant | Builder |
| Public fields with invariants | Invariant violation | Private + validated new() |
| 反模式 | 危害 | 替代方案 |
|---|---|---|
| 用布尔标志表示状态 | 运行时错误 | Type state |
| 用字符串表示语义类型 | 无类型安全 | Newtype |
| 用可选类型表示未初始化 | 不变式不清晰 | Builder |
| 带有不变式的公共字段 | 可能违反不变式 | 私有字段 + 已验证的new()方法 |
Related Skills
相关技能
| When | See |
|---|---|
| Domain modeling | m09-domain |
| Trait design | m04-zero-cost |
| Error handling in constructors | m06-error-handling |
| Anti-patterns | m15-anti-pattern |
| 场景 | 参考 |
|---|---|
| 领域建模 | m09-domain |
| Trait设计 | m04-zero-cost |
| 构造函数中的错误处理 | m06-error-handling |
| 反模式 | m15-anti-pattern |