ちょっとした気づきがあったのでメモ
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