19 个稳定版本

1.6.6 2024年2月13日
1.6.5 2021年4月25日
1.6.4 2020年11月25日
1.6.1 2020年10月28日
1.2.1 2020年8月29日

#1350 in 开发工具

Download history 21/week @ 2024-03-19 4/week @ 2024-03-26 72/week @ 2024-04-02 43/week @ 2024-04-09 152/week @ 2024-04-16 34/week @ 2024-04-23 39/week @ 2024-04-30 11/week @ 2024-05-07 19/week @ 2024-05-14 50/week @ 2024-05-21 11/week @ 2024-05-28 9/week @ 2024-06-04 21/week @ 2024-06-11 18/week @ 2024-06-18 11/week @ 2024-06-25 13/week @ 2024-07-02

64 每月下载量
waiter_di 中使用

MIT 许可证

40KB
861

Rust 的依赖注入

如何使用

Cargo.toml:

waiter_di = "1.6.5"

lib.rs 或任何其他使用库的文件

use waiter_di::*;

查看 examples/1_get_started.rs 以获取使用示例。

查看 examples/2_modules.rs 以获取带有模块和构造函数的示例。

查看 examples/3_inject_options_list.rs 以查看所有可用的注入选项的演示。

如何使用

使用 #[component] 注释结构体

#[component]
struct Comp {}

使用 #[provides] 注释 impl 块

#[provides]
impl Interface for Comp {}

创建容器

fn main() {
    let mut container = Container::<profiles::Default>::new();
}

获取依赖引用

fn main() {
    let comp = Provider::<dyn Interface>::get(&mut container);
}

注入引用

对于 Rc

#[component]
struct Dependency;

#[component]
struct Comp {
    dependency_rc: Rc<Dependency>
}

fn main() {
    let mut container = Container::<profiles::Default>::new();
    Provider::<Comp>::get(&mut container);
}

要使用 Arc 而不是 Rc,您需要在 cargo 中添加 async 功能

waiter_di = { version = "...", features = [ "async" ] }

您还可以使用 waiter_di::Wrc 类型,它将根据 async 功能编译为 RcArc

要创建新结构体而不是获取引用

#[component]
struct Comp {
    dependency: Dependency,
    dependency_box: Box<Dependency>
}

fn main() {
    let mut container = Container::<profiles::Default>::new();
    Provider::<Comp>::create(&mut container);
    Provider::<Comp>::create_boxed(&mut container);
}

属性

它在底层使用 config crate,例如它尝试在参数中作为 --float_prop <value> 查找 float_prop,如果没有找到,它尝试在环境变量中查找,之后尝试 config/{profile}.toml,之后 config/default.toml

#[derive(Debug, Deserialize)]
struct ConfigObject {
    i32_prop: i32
}

#[component]
struct Comp {
    config: Config,
    #[prop("int")] int_prop: usize,
    #[prop("int")] int_prop_opt: Option<usize>,
    #[prop("int" = 42)] int_prop_with_default_value: usize,
    float_prop: f32,
    #[prop] config_object: ConfigObject
}

依赖循环

使用 Deferred 类型

#[component]
struct Comp {
    dependency_def: Deferred<Dependency>,
    dependency_def_rc: Deferred<Rc<Dependency>>,
    dependency_def_box: Deferred<Box<Dependency>>
}

配置文件

您可以使用来自 `waiter_di::profile` 的预定义配置文件或创建自定义配置文件。

struct CustomProfile;

#[provides(profiles::Dev, CustomProfile)]
impl Interface for Comp {}

fn main() {
    let mut container = Container::<profiles::Default>::new();
    let mut container = Container::<profiles::Dev>::new();
    let mut container = Container::<CustomProfile>::new();
}

从参数、环境变量或 config/default.toml 获取配置文件

只需定义名为 profile 的属性作为 --profile <profile> 参数、profile 环境变量或 profileconfig/default.toml 中的属性,然后使用 inject!

fn main() {
    let comp = inject!(Comp: profiles::Default, profiles::Dev);
}

inject! 宏不能用于多个组件,因此建议与模块一起使用

#[module]
struct SomeModule {
    component: Component
}
#[module]
struct RootModule {
    some_module: SomeModule
}
fn main() {
    let root_module = inject!(RootModule: profiles::Default, profiles::Dev);
}

在这种情况下,#[module]#[component] 的同义词

工厂函数

如果不能使用 #[component] 注解,则使用工厂函数代替

#[provides]
fn create_dependency(bool_prop: bool) -> Dependency {
    Dependency { prop: bool_prop }
}

将其用作构造函数,请在 impl 块上使用 #[component]

struct Comp();

#[component]
impl Comp {
    #[provides]
    fn new() -> Self {
        Self()
    }
}

工厂函数不支持 Deferred 参数。在其他情况下,它可以接受与 #[component] 相同的参数类型。

工厂函数不支持外部类型

#[provides] // won't compile
fn create_external_type_dependency() -> HashMap<i32, i32> {
    HashMap::new()
}

因此,您需要创建 crate 本地包装器

struct Wrapper(HashMap<i32, i32>);

#[provides]
fn create_external_type_dependency() -> Wrapper {
    Wrapper(HashMap::new())
}

为了方便起见,您可以使用 #[wrapper] 属性来自动实现 Deref

#[wrapper]
struct HashMap(std::collections::HashMap<i32, i32>);

#[provides]
fn create_external_type_dependency() -> HashMap {
    return HashMap(std::collections::HashMap::<i32, i32>::new());
}

依赖关系

~3.5–4.5MB
~88K SLoC