Loading...
Loading...
Compare original and translation side by side
Layer 1: Language Mechanics
第一层:语言机制
| Pattern | Don't Just Say | Ask Instead |
|---|---|---|
| unwrap panics | "Use ?" | Is None/Err actually possible here? |
| Type mismatch on ? | "Use anyhow" | Are error types designed correctly? |
| Lost error context | "Add .context()" | What does the caller need to know? |
| Too many error variants | "Use Box<dyn Error>" | Is error granularity right? |
| 模式 | 不要只说 | 而是要问 |
|---|---|---|
| unwrap会触发panic | "使用?" | 这里真的可能出现None/Err吗? |
| ?运算符出现类型不匹配 | "使用anyhow" | 错误类型的设计是否正确? |
| 丢失错误上下文 | "添加.context()" | 调用者需要知道哪些信息? |
| 错误变体过多 | "使用Box<dyn Error>" | 错误的粒度是否合适? |
"Should I return Result or Option?"
↑ Ask: Is absence/failure normal or exceptional?
↑ Check: m09-domain (what does domain say?)
↑ Check: domain-* (error handling requirements)| Situation | Trace To | Question |
|---|---|---|
| Too many unwraps | m09-domain | Is the data model right? |
| Error context design | m13-domain-error | What recovery is needed? |
| Library vs app errors | m11-ecosystem | Who are the consumers? |
"我应该返回Result还是Option?"
↑ 询问:这种缺失/故障是正常情况还是异常情况?
↑ 查看:m09-domain(领域的要求是什么?)
↑ 查看:domain-*(错误处理的要求)| 场景 | 追溯到 | 问题 |
|---|---|---|
| unwrap过多 | m09-domain | 数据模型是否正确? |
| 错误上下文设计 | m13-domain-error | 需要什么样的恢复机制? |
| 库与应用的错误对比 | m11-ecosystem | 使用者是谁? |
"Expected failure, library code"
↓ Use: thiserror for typed errors
"Expected failure, application code"
↓ Use: anyhow for ergonomic errors
"Absence is normal (find, get, lookup)"
↓ Use: Option<T>
"Bug or invariant violation"
↓ Use: panic!, assert!, unreachable!
"Need to propagate with context"
↓ Use: .context("what was happening")"预期内故障,库代码"
↓ 使用:thiserror实现类型化错误
"预期内故障,应用程序代码"
↓ 使用:anyhow实现便捷的错误处理
"正常的缺失情况(查找、获取)"
↓ 使用:Option<T>
"Bug或违反不变量"
↓ 使用:panic!、assert!、unreachable!
"需要携带上下文传播错误"
↓ 使用:.context("当时正在执行的操作")| Pattern | When | Example |
|---|---|---|
| Recoverable error | |
| Absence is normal | |
| Propagate error | |
| Dev/test only | |
| Invariant holds | |
| Unrecoverable | |
| 模式 | 使用场景 | 示例 |
|---|---|---|
| 可恢复错误 | |
| 正常的缺失情况 | |
| 传播错误 | |
| 仅开发/测试环境 | |
| 不变量成立时 | |
| 不可恢复 | |
| Context | Error Crate | Why |
|---|---|---|
| Library | | Typed errors for consumers |
| Application | | Ergonomic error handling |
| Mixed | Both | thiserror at boundaries, anyhow internally |
| 上下文 | 错误库 | 原因 |
|---|---|---|
| 库 | | 为使用者提供类型化错误 |
| 应用程序 | | 便捷的错误处理体验 |
| 混合场景 | 两者都用 | 边界处用thiserror,内部用anyhow |
Is failure expected?
├─ Yes → Is absence the only "failure"?
│ ├─ Yes → Option<T>
│ └─ No → Result<T, E>
│ ├─ Library → thiserror
│ └─ Application → anyhow
└─ No → Is it a bug?
├─ Yes → panic!, assert!
└─ No → Consider if really unrecoverable
Use ? → Need context?
├─ Yes → .context("message")
└─ No → Plain ?故障是预期内的吗?
├─ 是 → 唯一的“故障”是缺失吗?
│ ├─ 是 → Option<T>
│ └─ 否 → Result<T, E>
│ ├─ 库 → thiserror
│ └─ 应用程序 → anyhow
└─ 否 → 这是一个bug吗?
├─ 是 → panic!、assert!
└─ 否 → 考虑是否真的不可恢复
使用? → 需要上下文吗?
├─ 是 → .context("消息")
└─ 否 → 直接使用?| Error | Cause | Fix |
|---|---|---|
| Unhandled None/Err | Use |
| Type mismatch | Different error types | Use |
| Lost context | | Add |
| Missing Result return | Return |
| 错误 | 原因 | 修复方案 |
|---|---|---|
| 未处理的None/Err | 使用 |
| 类型不匹配 | 错误类型不同 | 使用 |
| 丢失上下文 | 未携带上下文的? | 添加 |
| 返回类型不是Result | 返回 |
| Anti-Pattern | Why Bad | Better |
|---|---|---|
| Panics in production | |
| Ignore errors silently | Bugs hidden | Handle or propagate |
| Bad UX, no recovery | Result |
| Box<dyn Error> everywhere | Lost type info | thiserror |
| 反模式 | 危害 | 更好的做法 |
|---|---|---|
到处使用 | 生产环境中触发panic | 使用 |
| 静默忽略错误 | 隐藏bug | 处理或传播错误 |
对预期内错误使用 | 糟糕的用户体验,无法恢复 | 使用Result |
到处使用 | 丢失类型信息 | 使用thiserror |
| When | See |
|---|---|
| Domain error strategy | m13-domain-error |
| Crate boundaries | m11-ecosystem |
| Type-safe errors | m05-type-driven |
| Mental models | m14-mental-model |
| 场景 | 查看 |
|---|---|
| 领域错误策略 | m13-domain-error |
| 库边界 | m11-ecosystem |
| 类型安全错误 | m05-type-driven |
| 心智模型 | m14-mental-model |