m05-type-driven by zhanghandong/rust-skills
npx skills add https://github.com/zhanghandong/rust-skills --skill m05-type-driven第一层:语言机制
类型系统如何防止无效状态?
在寻求运行时检查之前:
| 模式 | 不要只是说 | 而是应该问 |
|---|---|---|
| 基本类型偏执 | "它只是一个字符串" | 这个值代表什么? |
| 布尔标志 | "添加一个 is_valid 标志" | 状态能否成为类型? |
| 到处使用可选类型 | "检查是否为 None" | 缺失状态真的可能发生吗? |
| 运行时验证 | "如果无效则返回 Err" | 我们能在构造时验证吗? |
在添加运行时验证之前:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
何时可以进行验证?
谁需要知道这个不变式?
当类型设计不明确时:
"需要验证电子邮件格式"
↑ 问:这是一个领域值对象吗?
↑ 检查: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 |
每周安装次数
636
代码仓库
GitHub 星标数
924
首次出现时间
Jan 20, 2026
安全审计
安装于
opencode580
codex563
gemini-cli554
github-copilot540
amp484
kimi-cli480
Layer 1: Language Mechanics
How can the type system prevent invalid states?
Before reaching for runtime checks:
| 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? |
Before adding runtime validation:
Can the type encode the constraint?
When is validation possible?
Who needs to know the invariant?
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? |
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()
| Pattern | Purpose | Example |
|---|---|---|
| Newtype | Type safety | struct UserId(u64); |
| Type State | State machine | Connection<Connected> |
| PhantomData | Variance/lifetime | PhantomData<&'a T> |
| Marker Trait | Capability flag | trait Validated {} |
| Builder | Gradual construction | Builder::new().name("x").build() |
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()))
}
}
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> { ... }
}
| 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 |
| 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() |
| When | See |
|---|---|
| Domain modeling | m09-domain |
| Trait design | m04-zero-cost |
| Error handling in constructors | m06-error-handling |
| Anti-patterns | m15-anti-pattern |
Weekly Installs
636
Repository
GitHub Stars
924
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode580
codex563
gemini-cli554
github-copilot540
amp484
kimi-cli480
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
103,800 周安装
Convex 应用安全检查清单 | 身份验证、函数暴露、参数验证、行级访问控制、环境变量安全
1,500 周安装
Convex HTTP Actions 教程:构建Webhook、API集成与自定义路由端点
1,500 周安装
微信小程序开发指南 - 腾讯云CloudBase集成、调试发布与项目结构最佳实践
1,600 周安装
arXiv语义搜索工具 - 使用自然语言查询物理、数学、计算机科学预印本论文
586 周安装
软件架构开发指南:整洁架构与DDD最佳实践,提升代码质量与可维护性
1,600 周安装
数据可视化专家指南:图表选择、设计原则与代码示例
1,500 周安装
| Sealed Trait | Prevent external impl | mod private { pub trait Sealed {} } |