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 日

#373Rust 模式

Download history 37/week @ 2024-04-12 19/week @ 2024-04-19 25/week @ 2024-04-26 25/week @ 2024-05-03 8/week @ 2024-05-10 10/week @ 2024-05-17 18/week @ 2024-05-24 28/week @ 2024-05-31 21/week @ 2024-06-07 20/week @ 2024-06-14 23/week @ 2024-06-21 20/week @ 2024-06-28 41/week @ 2024-07-05 17/week @ 2024-07-12 23/week @ 2024-07-19 13/week @ 2024-07-26

94 每月下载量
syrette_macros 中使用

MIT/Apache

190KB
4K SLoC

Syrette

Latest Version Documentation Build Coverage Rust

Syrette 是一个方便的 Rust 依赖注入与反转控制框架。

同名的

来自 Syrette 维基百科文章

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

功能

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

可选特性

  • 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 夜间版本的所有功能(例如 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

待办事项

  • 添加对泛型工厂的支持

贡献

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

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

依赖项

~1.8–2.5MB
~53K SLoC