#di #ioc #dependency-injection

teloc

简单、编译时 DI 框架,适用于 Rust

2 个不稳定版本

0.2.0 2021 年 11 月 25 日
0.1.0 2021 年 1 月 5 日

#1280 in Rust 模式

Download history 8/week @ 2024-03-11 3/week @ 2024-03-18 36/week @ 2024-04-01 1/week @ 2024-04-15 15/week @ 2024-04-22 8/week @ 2024-05-06 7/week @ 2024-05-27 18/week @ 2024-06-03 63/week @ 2024-06-17 45/week @ 2024-06-24

每月 127 次下载

MIT/Apache

40KB
656

teloc

teloc 是一个简单、编译时 DI 框架,受 C# 依赖注入框架 启发。

什么是 DI?

链接到维基百科

依赖注入 (DI) 是一种技术,其中对象接收其依赖的其他对象。这些其他对象被称为依赖。在典型的“使用”关系中,接收对象被称为客户端,传递的对象(即“注入”)被称为服务。将服务传递给客户端的代码可以是许多种类,称为注入器。客户端不指定它将使用哪种服务,而是注入器告诉客户端使用哪种服务。“注入”指的是将依赖(服务)传递给将使用它的对象(客户端)。

亮点

  • 编译时 - teloc 使用强大的 Rust 类型系统,在编译时进行生命周期和依赖存在性检查。这意味着如果您未为所有已注册的依赖项注册依赖项,或者依赖项的生命周期与请求者不匹配,则无法构建您的代码。如果您的代码编译成功,则表示它可以运行!
  • 无开销 - teloc 仅使用无开销抽象,如特质、泛型、新类型和单元类型,以及编译时依赖项解析,因此您不必担心运行时的开销。
  • 简单的 API - teloc 提供了一个简单的 API,只需一个结构和一个用于与库一起工作的属性宏即可。
  • 与现有环境的集成 - teloc 可以与任何现有框架一起使用,如 actix-web、warp、rocket。目前仅支持 actix-web,如您在 示例 中所看到的。

如何使用

有一个类型可以作为服务的提供者:ServiceProvider。它用作存储依赖项的存储库,具有 InstanceSingleton 生命周期,并使用 .add_*() 方法声明所有依赖项。它可以分支以创建具有局部实例的局部作用域。

依赖项有四种生命周期

  1. Transient。服务将在解析时创建。可以依赖于任何生命周期的依赖项。
  2. Singleton。在解耦时(延迟)在 ServiceProvider 中创建一次服务。可以依赖任何生命周期的依赖。不能依赖由分叉的 ServiceProvider 实例提供的服务。
  3. Instance。依赖项在 ServiceProvider 外部创建,并可以被任何其他依赖项使用。

工作原理

  1. 声明你的结构体。
  2. 创建构造函数,并在其上添加 #[inject] 宏。
  3. 创建一个 ServiceProvider 对象。
  4. 使用 ServiceProvider::add_* 方法添加你的服务和依赖项。
  5. 需要创建局部作用域时,分叉 ServiceProvider
  6. 使用 .resolve() 方法从提供者获取服务。
  7. 与服务一起工作。

示例

use teloc::*;

// Declare your structs
struct ConstService {
    number: i32,
}
// #[inject] macro is indicate that dependency can be constructed using this function
#[inject]
impl ConstService {
    pub fn new(number: i32) -> Self {
        ConstService { number }
    }
}

// Derive macro can be used when all fields implement `Dependency` trait, but 
// we recommend using the #[inject] macro it in production code instead.
#[derive(Dependency)]
struct Controller {
    number_service: ConstService,
}

fn main() {
    // Create `ServiceProvider` struct that store itself all dependencies
    let sp = ServiceProvider::new()
        // Add dependency with `Singleton` lifetime. More about lifetimes see above.
        .add_singleton::<ConstService>()
        // Add dependency with `Transient` lifetime. More about lifetimes see above.
        .add_transient::<Controller>();
    // Fork `ServiceProvider`. It creates a new `ServiceProvider` which will have
    // access to the dependencies from parent `ServiceProvider`.
    let scope = sp
        // .fork() method creates a local mutable scope with self parent immutable `ServiceProvider`.
        .fork()
        // Add an instance of `i32` that will be used when `ConstService` will be initialized.
        .add_instance(10);
    // Get dependency from `ServiceProvider`
    let controller: Controller = scope.resolve();
    assert_eq!(controller.number_service.number, 10);
}

有关文档,请参阅 docs.rs 上的页面

有关更多示例,请参阅 示例文件夹测试文件夹

与其他 DI 框架的比较

功能 teloc shaku waiter_di
编译时检查
可以在不使用 dyn 特性的情况下使用
一个应用程序中可以有多个服务提供者
不同的生命周期

如何读取错误

有时 teloc 可能会给出奇怪的大错误。但不要恐慌!你可以通过阅读 阅读错误的手册 来定义你的问题。

专业技巧

本节包含了一些专业技巧,你可能在使用库时想要使用。

获取 ServiceProvider 实例的类型

当你想要在结构体中存储 ServiceProvider 实例或从函数返回或作为参数传递时,这将很有用。

你需要

  1. ServiceProvider 初始化后粘贴以下代码:let () = service_provider;
  2. 编译器会给你一个非常大的可怕类型,以 teloc::ServiceProvider<...> 开头。
  3. 将此类型复制到类型别名中,例如 type ConcreteSP = /*编译器输出*/;
  4. 当你想要编写 ServiceProvider 实例类型时使用 ConcreteSP
  5. 如果更改 ServiceProvider 初始化,请重复步骤 1-4。

许可证

根据您的选择,许可为 Apache License, Version 2.0MIT 许可证
除非您明确声明,否则您有意提交以包含在此项目中的任何贡献,根据 Apache-2.0 许可证的定义,应按上述方式双许可,而无需任何附加条款或条件。

依赖关系

~2–7MB
~141K SLoC