17个不稳定版本 (8个破坏性更新)
| 0.9.1 | 2024年8月15日 |
|---|---|
| 0.9.0 | 2024年7月29日 |
| 0.8.1 | 2024年6月20日 |
| 0.8.0 | 2023年11月28日 |
| 0.2.0 | 2021年7月17日 |
#22 in 配置
1,555 每月下载量
47KB
857 行
这个包仍然处于早期阶段,需要大量的工作,但它在kamu-cli中被积极使用——这是一个根据Onion/Clean Architecture组织的相当大的项目。我们在遇到更复杂的DI场景时继续改进这个包。
示例
/////////////////////////////////////////
// Define interfaces in traits
trait A: Send + Sync {
fn test(&self) -> String;
}
// Implement traits to define components
#[component]
struct AImpl {
// Auto-inject dependencies (also supports by-value)
b: Arc<dyn B>,
}
impl A for AImpl {
fn test(&self) -> String {
format!("aimpl::{}", self.b.test())
}
}
/////////////////////////////////////////
trait B: Send + Sync {
fn test(&self) -> String;
}
#[component]
struct BImpl;
impl B for BImpl {
fn test(&self) -> String {
"bimpl".to_owned()
}
}
/////////////////////////////////////////
// Register interfaces and bind them to implementations
let cat = CatalogBuilder::new()
.add::<AImpl>()
.bind::<dyn A, AImpl>()
.add::<BImpl>()
.bind::<dyn B, BImpl>()
.build();
// Get objects and have their deps satisfied automatically
let inst = cat.get::<OneOf<dyn A>>().unwrap();
assert_eq!(inst.test(), "aimpl::bimpl");
功能
- 注入规范
OneOf- 期望给定接口的单个实现AllOf- 返回给定接口的所有实现的集合Maybe<Spec>- 如果内部Spec无法解析,则返回None
- 组件作用域
Transient(默认)- 对于每个调用创建一个新的实例Singleton- 在首次使用时创建一个实例,然后重用于其余调用
#[component]宏可以推导出Builder- 当直接用于
struct或具有Impl::new()函数的impl块时 - 可以注入为
Arc<T>,T: Clone,&T Option<T>被解释为Maybe<OneOf<T>>规范Vec<T>被解释为AllOf<T>规范- 支持在
Builder中使用自定义参数绑定 - 通过
#[interface]属性支持默认接口绑定 - 通过
#[meta(...)]属性支持元数据关联
- 当直接用于
- 支持预构建/按值添加支持
- 支持
Clone类型的按值注入 Catalog可以自我注入Catalog的链式操作允许动态添加值(例如在tower等中间件链中)
设计原则
- 非侵入式
- 编写适合依赖注入(DI)的代码应尽可能接近编写普通类型
- DI 应该是一个可添加的功能 - 我们应该能够禁用它并且所有代码都能编译(即允许依赖注入可选的库)
- 可扩展性
- 应该能够将 DI 功能添加到第三方代码中
- 关注 运行时 注入
- 利用类型系统和零成本抽象很棒,但很难做对 - 这个项目开始是因为我们急需一个实用的东西
- 有些情况涉及对象的动态注册(例如在处理 HTTP 请求期间添加身份验证令牌),这进一步复杂化了编译时的 DI
- 我们在可以容忍一些开销的情况下使用 DI 来集成粗粒度组件
- 我们通过提供运行时图验证来补偿安全性
- 关注 构造函数注入
- 基于字段/属性/访问器的注入会使系统复杂化,并且在我们经验中作用很小
- 将 实现权 交给实现者
- 类型实现者(而不是类型使用者)通常对类型的最佳生命周期和并发特性有最深入的了解,因此实现者应控制默认值
待办事项
- 支持
stableRust - 支持提供自身接口列表的构建器(默认绑定)
- 改进图验证
- 使
Scope成为Builder的外部,以便可以覆盖它们 - 允许动态注册(无需克隆整个目录)
- 考虑使用特质将
Arc、Option、Vec映射到依赖规范,而不是依赖于宏魔法 - 添加
trybuild测试(见 https://youtu.be/geovSK3wMB8?t=956) - 支持泛型类型
- 用泛型
add<B: Into<Builder>>替换add_* new()中的按引用传递值- 向错误添加低开销的解析堆栈(例如在 unwinding 时填充)
- 额外的作用域
- 调用
- 线程
- 任务
- 目录?
- 线程安全
- 懒值
- 外部定义的类型
- 自定义构建器
- 错误处理
- 文档测试
- 改进目录流畅接口(或宏?)
- 过程宏错误处理
- 构建一个未注册的类型
- 支持PImpl习语,其中
Arc<dyn Iface>可以被一个可移动对象隐藏- 这进一步隐藏了生命周期管理对消费者的可见性
- 允许实现泛型方法以改进
dyn Trait的可用性(例如,接受impl AsRef<str>参数而不是&str)
依赖关系
~0.4–0.8MB
~19K SLoC