I've got a trait in my application for working with users. I'm using a trait so that the clients aren't dependent on the actual implementation details - i.e. this way my HTTP handlers are dependent on State<Box<dyn UserService>>
and not State<UserServiceImpl<Database, MessageQueue>>
. That has been working great so far, up until now.
I'm now adding a method to my UserService to allow me to update user records. I'm doing this in a generic manner - to make it easy to implement PATCH requests - so my thinking was to do this:
trait UserService {
fn update_user<F: FnOnce(UserEntity) -> UserEntity>(
&self,
user_id: &UserID,
updater: F,
) -> Result<UserEntity, UpdateUserError>;
}
The idea is that I can then use this as follows:
let result = service.update_user(&user.identity.id, |user| {
if let Some(new_email_address) = new_email_address {
user.email_address = new_email_address;
}
if let Some(new_display_name) = new_display_name {
user.display_name = new_display_name;
}
});
And it now doesn't work. Because I now have a trait with a generic parameter, I can't create instances of it correctly. Instead I get:
error[E0038]: the trait `service::service::UserService` cannot be made into an object
--> crates/users/src/service/implementation.rs:21:6
|
21 | ) -> Box<dyn UserService> {
| ^^^^^^^^^^^^^^^^^^^^ the trait `service::service::UserService` cannot be made into an object
|
::: crates/users/src/service/service.rs:4:11
|
4 | pub trait UserService: Send + Sync {
| ----------- this trait cannot be made into an object...
...
43 | fn update_user<F: FnOnce(UserEntity) -> UserEntity>(
| ----------- ...because method `update_user` has generic type parameters
|
= help: consider moving `update_user` to another trait
This seems like it can't be an uncommon desire, so how do I best do this?
Cheers