m04-zero-cost by actionbook/rust-skills
npx skills add https://github.com/actionbook/rust-skills --skill m04-zero-cost第一层:语言机制
我们需要编译时多态还是运行时多态?
在泛型和特质对象之间做出选择之前,请考虑:
| 错误 | 不要只是说 | 而是应该问 |
|---|---|---|
| E0277 | "添加特质约束" | 这个抽象的层级合适吗? |
| E0308 | "修复类型" | 类型应该统一还是区分? |
| E0599 | "导入特质" | 这个特质是正确的抽象吗? |
| E0038 | "使其对象安全" | 我们真的需要动态分发吗? |
在添加特质约束之前:
需要什么样的抽象?
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
类型何时可知?
权衡的优先级是什么?
当类型系统"反抗"时:
E0277 (特质约束不满足)
↑ 问:抽象层级正确吗?
↑ 检查:m09-domain (正在抽象什么行为?)
↑ 检查:m05-type-driven (应该使用新类型吗?)
| 持续错误 | 追溯到 | 问题 |
|---|---|---|
| 复杂的特质约束 | m09-domain | 抽象正确吗? |
| 对象安全问题 | m05-type-driven | 类型状态能帮忙吗? |
| 类型爆炸 | m10-performance | 能接受 dyn 的开销吗? |
从设计到实现:
"需要对具有相同行为的类型进行抽象"
↓ 类型在编译时已知 → `impl Trait` 或泛型
↓ 类型在运行时确定 → `dyn Trait`
"需要不同类型的集合"
↓ 封闭集合 → 枚举
↓ 开放集合 → `Vec<Box<dyn Trait>>`
"需要返回不同类型"
↓ 相同类型 → `impl Trait`
↓ 不同类型 → `Box<dyn Trait>`
| 模式 | 分发方式 | 代码大小 | 运行时成本 |
|---|---|---|---|
fn foo<T: Trait>() | 静态 | +膨胀 | 零 |
fn foo(x: &dyn Trait) | 动态 | 最小 | 虚表查找 |
impl Trait 返回值 | 静态 | +膨胀 | 零 |
Box<dyn Trait> | 动态 | 最小 | 分配 + 虚表 |
// 静态分发 - 类型在编译时已知
fn process(x: impl Display) { } // 参数位置
fn process<T: Display>(x: T) { } // 显式泛型
fn get() -> impl Display { } // 返回位置
// 动态分发 - 类型在运行时确定
fn process(x: &dyn Display) { } // 引用
fn process(x: Box<dyn Display>) { } // 拥有所有权
| 错误 | 原因 | 快速修复 |
|---|---|---|
| E0277 | 类型未实现特质 | 添加实现或更改约束 |
| E0308 | 类型不匹配 | 检查泛型参数 |
| E0599 | 未找到方法 | 使用 use 导入特质 |
| E0038 | 特质非对象安全 | 使用泛型或重新设计 |
| 场景 | 选择 | 原因 |
|---|---|---|
| 性能关键 | 泛型 | 零运行时成本 |
| 异构集合 | dyn Trait | 运行时类型不同 |
| 插件架构 | dyn Trait | 编译时类型未知 |
| 减少编译时间 | dyn Trait | 减少单态化 |
| 小型、已知类型集合 | enum | 无间接寻址 |
一个特质是对象安全的,如果它:
Self: Sized 约束Selfwhere Self: Sized| 反模式 | 为何不好 | 更好的做法 |
|---|---|---|
| 过度泛化一切 | 编译时间、复杂性 | 可能时使用具体类型 |
对已知类型使用 dyn | 不必要的间接寻址 | 泛型 |
| 复杂的特质层次结构 | 难以理解 | 更简单的设计 |
| 忽略对象安全性 | 限制灵活性 | 如果需要,为 dyn 做规划 |
| 时机 | 参见 |
|---|---|
| 类型驱动设计 | m05-type-driven |
| 领域抽象 | m09-domain |
| 性能考量 | m10-performance |
| Send/Sync 约束 | m07-concurrency |
每周安装量
41
代码仓库
GitHub 星标数
809
首次出现
2026年1月23日
安全审计
安装于
gemini-cli38
codex37
opencode36
claude-code32
github-copilot32
cursor31
Layer 1: Language Mechanics
Do we need compile-time or runtime polymorphism?
Before choosing between generics and trait objects:
| Error | Don't Just Say | Ask Instead |
|---|---|---|
| E0277 | "Add trait bound" | Is this abstraction at the right level? |
| E0308 | "Fix the type" | Should types be unified or distinct? |
| E0599 | "Import the trait" | Is the trait the right abstraction? |
| E0038 | "Make object-safe" | Do we really need dynamic dispatch? |
Before adding trait bounds:
What abstraction is needed?
When is type known?
What's the trade-off priority?
When type system fights back:
E0277 (trait bound not satisfied)
↑ Ask: Is the abstraction level correct?
↑ Check: m09-domain (what behavior is being abstracted?)
↑ Check: m05-type-driven (should use newtype?)
| Persistent Error | Trace To | Question |
|---|---|---|
| Complex trait bounds | m09-domain | Is the abstraction right? |
| Object safety issues | m05-type-driven | Can typestate help? |
| Type explosion | m10-performance | Accept dyn overhead? |
From design to implementation:
"Need to abstract over types with same behavior"
↓ Types known at compile time → impl Trait or generics
↓ Types determined at runtime → dyn Trait
"Need collection of different types"
↓ Closed set → enum
↓ Open set → Vec<Box<dyn Trait>>
"Need to return different types"
↓ Same type → impl Trait
↓ Different types → Box<dyn Trait>
| Pattern | Dispatch | Code Size | Runtime Cost |
|---|---|---|---|
fn foo<T: Trait>() | Static | +bloat | Zero |
fn foo(x: &dyn Trait) | Dynamic | Minimal | vtable lookup |
impl Trait return | Static | +bloat | Zero |
Box<dyn Trait> | Dynamic | Minimal | Allocation + vtable |
// Static dispatch - type known at compile time
fn process(x: impl Display) { } // argument position
fn process<T: Display>(x: T) { } // explicit generic
fn get() -> impl Display { } // return position
// Dynamic dispatch - type determined at runtime
fn process(x: &dyn Display) { } // reference
fn process(x: Box<dyn Display>) { } // owned
| Error | Cause | Quick Fix |
|---|---|---|
| E0277 | Type doesn't impl trait | Add impl or change bound |
| E0308 | Type mismatch | Check generic params |
| E0599 | No method found | Import trait with use |
| E0038 | Trait not object-safe | Use generics or redesign |
| Scenario | Choose | Why |
|---|---|---|
| Performance critical | Generics | Zero runtime cost |
| Heterogeneous collection | dyn Trait | Different types at runtime |
| Plugin architecture | dyn Trait | Unknown types at compile |
| Reduce compile time | dyn Trait | Less monomorphization |
| Small, known type set | enum | No indirection |
A trait is object-safe if it:
Self: Sized boundSelfwhere Self: Sized for non-object-safe methods| Anti-Pattern | Why Bad | Better |
|---|---|---|
| Over-generic everything | Compile time, complexity | Concrete types when possible |
dyn for known types | Unnecessary indirection | Generics |
| Complex trait hierarchies | Hard to understand | Simpler design |
| Ignore object safety | Limits flexibility | Plan for dyn if needed |
| When | See |
|---|---|
| Type-driven design | m05-type-driven |
| Domain abstraction | m09-domain |
| Performance concerns | m10-performance |
| Send/Sync bounds | m07-concurrency |
Weekly Installs
41
Repository
GitHub Stars
809
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli38
codex37
opencode36
claude-code32
github-copilot32
cursor31
ESLint迁移到Oxlint完整指南:JavaScript/TypeScript项目性能优化工具
1,600 周安装
ast-grep 代码搜索:基于抽象语法树(AST)的智能结构化代码搜索工具
2,400 周安装
Three.js 着色器教程:ShaderMaterial与RawShaderMaterial完整指南
2,400 周安装
TanStack Query v5 完全指南:React 数据管理、乐观更新、离线支持
2,500 周安装
Stripe API 版本升级指南:SDK、Stripe.js 和移动端SDK更新教程
2,500 周安装
UI/UX设计系统专家:基于TailwindCSS+Radix UI+shadcn/ui的现代Web应用设计与开发
2,500 周安装
GitHub趋势数据抓取指南:获取热门仓库与开发者数据(无官方API解决方案)
2,500 周安装