作为我的铁 rust 学习过程的一部分,我正在try 转换我已经使用过几次的图案.这是通过密钥(通常是接口名称)注册的"服务"的存储库.然后,可以查询该存储库以检索随后可以使用的"服务".我过go 曾将其用作简单的DI方法,以允许在测试期间将实现替换为模拟.
我在Rust中实现这一简单版本时遇到了一些问题.
我希望看到的是这样的代码:
// The service contract
trait DoSomethingService {
fn do_something(&self);
}
// The service implementation
struct DoSomethingServiceImpl {}
impl DoSomethingService for DoSomethingServiceImpl {
fn do_something(&self) {
println!("Doing something for MyService");
}
}
// BaseService is a marker trait
impl BaseService for DoSomethingServiceImpl {}
fn main() {
let mut repo = ServiceRepo::new();
let service1 = DoSomethingServiceImpl {};
// Register our implementation with the repo as the trait DoSomethingService
repo.register_service::<DoSomethingService>(Box::new(service1));
// Get the service from the repo and have it cast to the trait NOT the concrete type
if let Some(x) = repo.get_service::<DoSomethingService>() {
x.do_something();
}
}
我当前的实现如下所示
#[derive(Default)]
struct ServiceRepo {
services: HashMap<String, Box<dyn BaseService>>,
}
impl ServiceRepo {
fn new() -> Self {
Self {
..Default::default()
}
}
fn register_service<T: BaseService>(&mut self, service: Box<dyn BaseService>) {
self.services
.insert(std::any::type_name::<T>().to_string(), service);
}
fn get_service<T: BaseService>(&self) -> Option<&Box<T>> {
let service = self.services.get(&std::any::type_name::<T>().to_string());
// TODO: Want to return an Option<&T> here
// Not sure what to do!
}
}
我"认为"我很好地存储了服务实现,但将其预定义为所需的特征却在回避我.
所以有几个问题:
- 这是《铁 rust 》中的一个合理模式吗?如果不是,原因何在?
- 我将如何实现这一点?我现在错过了什么?