#di #ioc #inversion-of-control #dependency-injection

syrette_macros

为 Syrette 轻便依赖注入框架提供的宏

10 个版本

0.5.1 2023 年 10 月 1 日
0.5.0 2023 年 9 月 21 日
0.4.2 2022 年 11 月 28 日
0.4.1 2022 年 10 月 30 日
0.1.1 2022 年 7 月 22 日

#1011过程宏

Download history 22/week @ 2024-04-14 22/week @ 2024-04-21 34/week @ 2024-04-28 24/week @ 2024-05-05 16/week @ 2024-05-12 11/week @ 2024-05-19 28/week @ 2024-05-26 32/week @ 2024-06-02 23/week @ 2024-06-09 21/week @ 2024-06-16 30/week @ 2024-06-23 22/week @ 2024-06-30 48/week @ 2024-07-07 25/week @ 2024-07-14 24/week @ 2024-07-21 23/week @ 2024-07-28

每月 125 次下载
2 个 crates 中使用 (通过 syrette)

MIT/Apache

130KB
3.5K SLoC

Syrette

Latest Version Documentation Build Coverage Rust

Rust 的便捷依赖注入和反转控制框架。

命名来源

来自 Syrette 维基百科文章

注射器是一种通过针头注入液体的装置。它类似于注射器,但有一个封闭的柔性管(类似于通常用于牙膏的管子)而不是刚性管和活塞。

特性

  • 依赖注入和反转控制容器
  • 自动绑定依赖项
  • 灵感来源于 InversifyJS 的 API
  • 有用的错误信息
  • 支持泛型实现和泛型接口特质
  • 绑定单例
  • 注入第三方结构体和特质
  • 命名绑定
  • 异步工厂

可选功能

  • factory. 绑定工厂(Rust 夜间版本所需)
  • prevent-circular. 循环依赖的检测和预防。 (默认启用)
  • async. 异步支持

要使用这些功能,您必须在 Cargo 中启用它

为什么要反转控制和依赖注入?

实践 IoC 和 DI 的原因是编写模块化和松耦合的应用程序。

这是我们试图避免的

impl Foo
{
    /// ❌ Bad. Foo knows the construction details of Bar.
    pub fn new() -> Self
    {
        Self {
            bar: Bar::new()
        }
    }

以下更好

impl Foo
    /// ✅ Better. Foo is unaware of how Bar is constructed.
    pub fn new(bar: Bar) -> Self
    {
        Self {
            bar
        }
    }
}

但是,当您有一个具有许多依赖项的大型代码库及其依赖项时,这迟早会变得相当繁琐。因为您必须在某个地方指定依赖项

let foobar = Foobar::new(
    Foo:new(
        Woof::new(),
        Meow::new()),
    Bar::new(
        Something::new(),
        SomethingElse::new(),
        SomethingMore::new()
    )
)

这就是 Syrette 出现的原因。

动机

其他Rust的DI和IoC库要么是未维护的(例如di),要么过于复杂且需要Rust nightly版本才能使用所有功能(例如anthill-di),或者API很奇怪(例如teloc)。

Syrette的目标是成为一个简单、有用、方便且熟悉的DI和IoC库。

示例用法

use std::error::Error;

use syrette::injectable;
use syrette::DIContainer;
use syrette::ptr::TransientPtr;

trait IWeapon
{
	fn deal_damage(&self, damage: i32);
}

struct Sword {}

#[injectable(IWeapon)]
impl Sword
{
	fn new() -> Self
	{
		Self {}
	}
}

impl IWeapon for Sword
{
	fn deal_damage(&self, damage: i32)
	{
		println!("Sword dealt {} damage!", damage);
	}
}

trait IWarrior
{
	fn fight(&self);
}

struct Warrior
{
	weapon: TransientPtr<dyn IWeapon>,
}

#[injectable(IWarrior)]
impl Warrior
{
	fn new(weapon: TransientPtr<dyn IWeapon>) -> Self
	{
		Self { weapon }
	}
}

impl IWarrior for Warrior
{
	fn fight(&self)
	{
		self.weapon.deal_damage(30);
	}
}

fn main() -> Result<(), Box<dyn Error>>
{
	let mut di_container = DIContainer::new();

	di_container.bind::<dyn IWeapon>().to::<Sword>()?;

	di_container.bind::<dyn IWarrior>().to::<Warrior>()?;

	let warrior = di_container.get::<dyn IWarrior>()?.transient()?;

	warrior.fight();

	println!("Warrior has fighted");

	Ok(())
}

更多示例请参见示例文件夹

术语

瞬态
一个类型或特质,对于所有者来说是唯一的。

单例
只有一个实例的类型。与瞬态相反。通常不鼓励使用。

接口
表示类型的类型或特质(如果是类型,则是自身)。

工厂
一个函数,用于创建特定类型或特质的实例。

默认工厂
一个不接受任何参数的函数,用于创建特定类型或特质的实例。

Rust版本要求

Syrette需要Rust >= 1.62.1才能运行。这主要是由于依赖于Linkme

待办事项

  • 添加对泛型工厂的支持

贡献

您可以通过加入邮件列表来联系我们。

这是提交补丁、功能请求和报告错误的地方。


lib.rs:

Syrette包提供的宏。

依赖项

~0.6–1.6MB
~31K SLoC