asynchronousrusttraitsdynamic-dispatch

for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically


I'm on the nightly version

#![feature(async_fn_in_trait)]

use std::sync::Arc;

trait IUserRepository {
    async fn find_by_email(&self, email: &str) -> bool;
}

struct Container {
    user_repositpory: Arc<dyn IUserRepository>
}

and when I run this code shows this error:

error[E0038]: the trait `IUserRepository` cannot be made into an object
  --> src/main.rs:14:27
   |
14 |     user_repositpory: Arc<dyn IUserRepository>
   |                           ^^^^^^^^^^^^^^^^^^^ `IUserRepository` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>

how can I fix that?


Solution

  • 1 - solution one:

    Using generics

    #![feature(async_fn_in_trait)]
    
    use std::sync::Arc;
    
    trait IUserRepository {
        async fn find_by_email(&self, email: &str) -> bool;
    }
    
    struct Container<T> where T: IUserRepository {
        user_repositpory: Arc<T>
    }
    

    2 - solution two:

    using stable version and async-trait crate.

    use async_trait::async_trait;
    use std::sync::Arc;
    
    #[async_trait]
    trait IUserRepository {
        async fn find_by_email(&self, email: &str) -> bool;
    }
    
    struct Container {
        user_repositpory: Arc<dyn IUserRepository>,
    }
    

    3 - solution three:

    Using the future this solution is exactly what async-trait do. Follow This Link

    #![feature(async_fn_in_trait)]
    
    use std::{future::Future, sync::Arc};
    
    trait IUserRepository {
        fn find_by_email<'a, 'b>(&'a self, email: &'b str) -> Box<dyn Future<Output = bool> + '_>;
    }
    
    struct Container {
        user_repositpory: Arc<dyn IUserRepository>,
    }