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 来集成粗粒度组件
- 我们通过提供运行时图验证来补偿安全性
- 关注 构造函数注入
- 基于字段/属性/访问器的注入会使系统复杂化,并且在我们经验中作用很小
- 将 实现权 交给实现者
- 类型实现者(而不是类型使用者)通常对类型的最佳生命周期和并发特性有最深入的了解,因此实现者应控制默认值
待办事项
- 支持
stable
Rust - 支持提供自身接口列表的构建器(默认绑定)
- 改进图验证
- 使
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