1 个不稳定版本
0.1.0 | 2019年6月4日 |
---|
#389 在 构建工具 中
在 kamikaze_di_derive 中使用
37KB
525 行
Kamikaze DI
这是一个 Rust 的依赖注入容器。它受到了其他语言容器库的启发。
我主要想知道人们对它的看法,以及是否有人想使用这样的东西。
它的工作原理
let config = container.resolve::<Config>(); // simple resolve via the Resolver trait
let config: Config = cotantiner.inject(); // using Injector and Inject/InjectAsRc
// deriving the Inject trait teaches the container how to create it
#[derive(Inject, Clone)]
struct DabatabaseConnection {
config: Config,
...
}
有关更多信息,请参阅示例和文档。
安装
获取基础 crate 和 derive crate。
[dependencies]
kamikaze_di = "0.1.0"
kamikaze_di_derive = "0.1.0"
# or use this for slightly better debug! logs in the derive crate
# log = "0.4.6"
# kamikaze_di_derive = { version = "0.1.0", features="logging" }
这需要 rust nightly。
讨论
Rust 有两个重要概念:所有权和可变性。这两个概念都影响了我们 DI 容器的设计。
所有权
数据只能有一个所有者,所以在进行操作时,谁拥有什么
let db = container.resolve::<Database>();
db 对象来自容器内部。它必须在某个时候拥有它,现在当前作用域拥有了它。那么当我们再次解析 Database 时会发生什么呢?
工厂
一种方法是让容器充当工厂。虽然有时这是所希望的(并通过 .register_factory::<T>()
支持),但这绝对不是合理的默认设置,我们如何共享东西呢?
副本
如果我们返回前复制或克隆对象,那么我们可以共享东西。但有些东西可能永远不应该共享。
克隆不可克隆的?
其他语言没有这个问题,因为所有东西都存在于堆中,并且是引用计数的。听起来像是 Rc<>,不是吗。
使用 Rc
容器构建器上所有注册函数的类型签名类似于
fn register<T>(&mut self, item: T) -> Result<()> where T: Clone
我们始终需要 Clone,一些类型可以接受这个。对于其他类型,你可以使用 Rc。
let database = ...;
builder.register(Rc::new(database));
Rc 也可以与特性对象一起使用
let database: MysqlConnection = ...;
builder.register::<Rc<Database>>(Rc::new(database));
为什么不使用 &T 呢?
我早期就决定使用 Clone/Rc,但我非常不确定这是否是正确的选择。
关于可变性怎么办?
如果你正在获取克隆对象,可变性是你的责任。如果你正在使用 Rc,情况就不同了:Rc::get_mut() 总是返回 None,因为容器总是会保持对其的引用。你需要使用内部可变性。
关于 Sync 呢?
这是一个非常好的问题。
基本上,我不想添加它。我只是想开始一场讨论,我不想维护一个我自己都不会使用的工具,而且我写的 Rust 代码还不够多,无法做到这一点。
自动推导
如果 AutoResolvable
特性在作用域内,容器将尝试自己找出如何创建依赖项。这通常会在运行时通过反射来完成,但 Rust 不支持这一点。
任何实现了 Inject
或 InjectAsRc
的类型都可以以这种方式解决。当然,自己编写所有这些代码是非常繁琐的。所以为什么不直接推导呢?
// Just derive this trait
#[derive(Inject, Clone)]
struct YourStruct {
// ...
}
所有这些类型的依赖项都需要推导 Inject
、InjectAsRc
或在容器中注册。
错误
当类型无法解决时,你会得到相当不错的错误信息。以下是 unwrapping 错误时你会得到的内容。
could not resolve Jester::voice_box : Rc < VoiceBox > ...
这并不完美,错误信息没有使用类型的完整路径,但它可能足以确定出了什么问题。
恐慌
此项目仅在循环依赖的情况下应该恐慌,任何其他恐慌都是错误。
示例
在 repo 和文档中都有示例。
依赖项
~87KB