架构设计
第一步:定义依赖的 trait 和实现
// path/to/domain/foo_service.rs:
pub trait FooService {
fn foo_bar(&self);
}
声明结构体 FooServiceState
并实现 FooService
,使用
dep-inj 库。
以下是宏展开后的等效代码:
// path/to/service/foo_service.rs:
use path::to::domain::FooService;
#[derive(dep_inj::DepInj)]
#[target(FooServiceImpl)]
pub struct FooServiceState {
bar: u64
}
impl FooServiceState {
pub fn new(bar: u64) -> Self {
Self {
bar
}
}
}
/// 该结构体的方法不调用其他结构体的方法,
/// 意味着它不依赖任何其他结构体。
/// 因此实际上无需为其派生 DepInj。
/// 以下代码即可实现:
/// ```rust
/// pub struct FooServiceImpl { bar: u64 }
/// impl FooService for FooServiceImpl {
/// fn foo_bar(&self) {
/// println!("{}", self.bar);
/// }
/// }
/// ```
/// 此处使用 DepInj 仅作示例。
/// 若需访问 state 中的字段,必须显式指定
impl<Deps> FooService for FooServiceImpl<Deps>
where
Deps: AsRef<FooServiceState>
{
fn foo_bar(&self) {
/// &self 自动通过 as_ref 转为 FooServiceState,故可访问其字段
println!("{}", self.bar);
}
}
// DepInj 宏展开后生成的代码:
#[repr(transparent)]
/// __Deps__ 指定了类型解引用所需实现的 trait
pub struct FooServiceImpl<__Deps__: ?Sized> {
/// To pass compile
_marker: ::core::marker::PhantomData<FooServiceState>,
deps: __Deps__,
}
impl<__Deps__> Copy for FooServiceImpl<__Deps__> where __Deps__: Copy {}
/// 为 Impl 实现 Deref 到 State
impl<__Deps__: ?Sized> ::core::ops::Deref for FooServiceImpl<__Deps__>
where
__Deps__: AsRef<FooServiceState>,
{
type Target = FooServiceState;
#[inline]
fn deref(&self) -> &Self::Target {
self.deps.as_ref()
}
}
impl<__Deps__: ?Sized> ::core::ops::DerefMut for FooServiceImpl<__Deps__>
where
__Deps__: AsRef<FooServiceState> + AsMut<FooServiceState>,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.deps.as_mut()
}
}
impl<__Deps__> From<FooServiceImpl<__Deps__>> for FooServiceState
where
__Deps__: Into<FooServiceState>,
{
fn from(value: FooServiceImpl<__Deps__>) -> Self {
value.prj().into()
}
}
impl<__Deps__> Clone for FooServiceImpl<__Deps__>
where
__Deps__: Clone,
{
fn clone(&self) -> Self {
Self {
_marker: ::core::marker::PhantomData,
deps: self.deps.clone(),
}
}
}
//...
// Some factory methods
// inj method is to transfer a borrow of generic type __Deps__
// to Self(FooServiceImpl<__Deps__> here).
// pri method is to transfer a borrow of self to a borrow of generic type __Deps__.
impl<__Deps__: ?Sized> FooServiceImpl<__Deps__> {
#[inline]
pub fn inj_ref(deps: &__Deps__) -> &Self {
unsafe { &*(deps as *const __Deps__ as *const Self) }
}
#[inline]
pub fn prj_ref(&self) -> &__Deps__ {
unsafe { &*(self as *const Self as *const __Deps__) }
}
#[inline]
pub fn inj_ref_mut(deps: &mut __Deps__) -> &mut Self {
unsafe { &mut *(deps as *mut __Deps__ as *mut Self) }
}
#[inline]
pub fn prj_ref_mut(&mut self) -> &mut __Deps__ {
unsafe { &mut *(self as *mut Self as *mut __Deps__) }
}
//...
}
impl<__Deps__> FooServiceImpl<__Deps__> {
#[inline]
pub fn inj(deps: __Deps__) -> Self {
Self {
_marker: ::core::marker::PhantomData,
deps,
}
}
#[inline]
pub fn prj(self) -> __Deps__ {
self.deps
}
}
第二步:编写容器(Container)
容器用于持有所有状态,并在 boilerplate 中通过宏生成的 inj 方法为容器实现所有 trait。
使用 derive_more::AsRef 为容器添加 AsRef<FooService>
能力,可以在 &Contaner 使用 inj_ref 之后,使用 FooService 的方法:
代码:
// path/to/container.rs
// The Service need to use Other dependencies only need to depend on Container
#[derive(derive_more::AsRef)]
pub struct Container {
#[as_ref]
pub foo_service: FooServiceState,
}
impl Container {
// Initialize method for Container.
pub fn new(config: &AppConfig) -> Self {
let foo_service = FooServiceState::new(config.num);
Self {
foo_service
}
}
}
// .../boilerplate.rs
use path::to::Container;
use path::to::domain::FooService;
use path::to::foo_service::FooServiceImpl;
use path::to::bar_service::BarServiceImpl;
// Boilerplate for provide FooService implement for Container
impl FooService for Container {
fn foo_bar(&self) {
// Use inj_ref() generated by dep-inj macro,
// to get &FooServiceImpl from Container
FooServiceImpl::inj_ref(self).foo_bar()
}
}
impl BarService for Container {
fn bar_foo(&self) {
BarServiceImpl::inj_ref(self).bar_foo()
}
}
第三步:实现依赖其他服务的结构体
然后,我们编写 Barservice
,他依赖于 Fooservice
。
dep_inj_target
宏用于在无字段结构体上生成 dep_inj
。
代码:
// path/to/bar_service.rs
// Use of the Dependency Injection System!
use path::to::domain::FooService;
#[dep_inj_target::dep_inj_target]
pub struct BarServiceImpl;
impl<Deps> BarServiceImpl<Deps>
where
Deps: FooService
{
pub fn bar_foo(&self) {
// 2. Use deref mechanism to auto use method under trait `FooService`
self.prj_ref().foo_bar()
// Or `(self.prj_ref() as &dyn FooService).foo_bar()`
}
}
最终调用示例
最终,我们可以通过 Entry 去调用 BarServiceImpl
中的 bar_foo
方法,在 bar_foor
中,又调用了 FooServiceImpl
的 foo_bar
方法!
代码:
// .../entry.rs
use path::to::Container;
pub struct Entry {
container: Container
}
impl Entry {
fn run_bar_foo(&self) {
// The container implements the `FooService` bound, so it can satisfy
// `BarServiceImpl`'s call on `bar_foo()`.
// in `bar_foo`, it converts to a reference to `Deps`,
// which can call `foo_bar` from `FooService`
// because the Container implements the `FooService` with call of `FooServiceImpl`'s `inj_ref` method
// and AsRef<FooServiceState>(generated by derive(AsRef)), the foo_bar method can be called successfully!
self.container.bar_foo();
// Or (self.container as dyn BarService).bar_foo()
}
}
核心机制总结
-
依赖推导: 容器通过 AsRef 自动推导依赖关系,满足 trait 约束。
-
零成本抽象: 使用宏生成的 inj_ref 方法,无需运行时开销即可转换类型引用。
-
编译期约束: 所有依赖的 Send/Sync 约束会在编译期递归检查,确保线程安全。
-
灵活扩展: 新增服务只需实现对应 trait 并注册到容器,无需修改已有代码。
注意事项
在此架构中,deps 会递归地接受所有依赖字段的 Send 和 Sync 约束的交集。
这意味着,如果你想为 Arc<Self>
类型实现函数,一旦某个依赖在容器中是 !Sync
的,整个容器将无法通过编译检查。
例如:
impl<Deps> A for AImpl<Deps>
where
Deps: AsRef<AImpl> + B + Send
{
fn aa(self: Arc<Self>){
// your logic here
}
}
如果 BImplState 中有任何字段是 !Sync 的,整个代码将无法通过编译,因为 Arc<Self>
要求整个 Deps 必须满足 Send 和 Sync trait 约束,但某个字段缺少 Sync 约束。