m04-zero-cost by zhanghandong/rust-skills
npx skills add https://github.com/zhanghandong/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) | 动态 | 最小 | vtable 查找 |
impl Trait 返回 | 静态 | +膨胀 | 零 |
Box<dyn Trait> | 动态 | 最小 | 分配 + vtable |
// 静态分发 - 编译时已知类型
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 |
每周安装量
639
代码仓库
GitHub 星标数
912
首次出现
2026年1月20日
安全审计
安装于
opencode584
codex569
gemini-cli558
github-copilot545
amp496
kimi-cli491
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
639
Repository
GitHub Stars
912
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode584
codex569
gemini-cli558
github-copilot545
amp496
kimi-cli491
Vue.js Options API 最佳实践与 TypeScript 集成指南 - 解决常见开发问题
1,000 周安装