LoginSignup
25
14

More than 5 years have passed since last update.

RustでDI(依存注入)する

Last updated at Posted at 2019-02-09

ちょっとした気づきがあったのでメモ

dyn Traitを用いたDI

アプリケーションを設計する上でClean ArchitectureなどDIを多用するケースがありますが、Rustで実装するにあたり構造体フィールドに対して dyn Trait を用いた動的ディスパッチのみが実現方法だと私は勘違いしていました。

struct UserInteractor {
    user_repository: Box<dyn UserRepository>,
}

impl UserInteractor {
    fn get_all_user(&self) -> Vec<User> {
        self.user_repository.get_all_user()
    }
}

Genericsを用いたDI

一方でGenericsを用いたDIも可能だったようで、コードに起こすと以下のようになります。

struct UserInteractor<T>
where
    T: UserRepository,
{
    user_repository: T,
}

impl<T: UserRepository> UserInteractor<T> {
    fn get_all_user(&self) -> Vec<User> {
        self.user_repository.get_all_user()
    }
}

Genericsを用いた構造体定義が可能なものとは理解していたのですが、この場合のメソッド定義方法が分からず頓挫していました。
今思うとimplキーワードにTrait境界を記述するだけでした。

以下はClean Architecture風の雑な一連のコードです。

#[derive(Debug)]
struct User {}

trait UserRepository {
    fn get_all_user(&self) -> Vec<User>;
}

struct MockUserRepository {}

impl UserRepository for MockUserRepository {
    fn get_all_user(&self) -> Vec<User> {
        vec![User {}]
    }
}

struct UserInteractor<T>
where
    T: UserRepository,
{
    user_repository: T,
}

impl<T: UserRepository> UserInteractor<T> {
    fn get_all_user(&self) -> Vec<User> {
        self.user_repository.get_all_user()
    }
}

fn main() {
    let user_repository = MockUserRepository {};
    let user_interactor = UserInteractor { user_repository };
    let users = user_interactor.get_all_user();
    println!("{:?}", users);
}

Rust ver 1.32.0

25
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
14