ferd tomale
ferd tomale

Reputation: 903

How to fix `trait cannot be made into a trait object`?

I have the following code:

pub trait Service {}

#[derive(Clone)]
pub struct Services {
    providers: std::collections::HashMap<String, Box<dyn Service>>
}

which gives this error:

the trait `Clone` is not implemented for `dyn Service`

I also tried changing Service to pub trait Service: Clone {} but it gave me a different error that the trait cannot be made into an object because it is not object_safe (because it requires Self::Sized.

playground - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=eecca2b2bd82d4df4c34f44463594c58

Upvotes: 0

Views: 975

Answers (2)

Zeppi
Zeppi

Reputation: 1235

You can add Clone in the definition of the type that is enclosed in Box.

Something like this

use std::collections::HashMap;

pub trait Service {}

#[derive(Clone)]
pub struct Services<T>
    where
        T: Service, //<--------
        T: Clone //<----------- {
    providers: std::collections::HashMap<String, Box<T>>
}

#[derive(Clone)]
pub struct A{}

impl Service for A {}

fn main()
{
    let mut v: HashMap<String, Box<A>> = HashMap::new();
    v.insert("test".to_string(), Box::new(A{}));
    
    let o = Services{providers: v };
    
    for (key, _) in o.providers.iter() {
        println!("key: {} ", key);
    }
}

The Sean version could be like this

use std::collections::HashMap;
use std::sync::Arc;

pub trait Service {}

#[derive(Clone)]
pub struct Services {
    providers: Arc<std::collections::HashMap<String, Box<dyn Service>>>
}

#[derive(Clone)]
pub struct A{}
impl Service for A {}

#[derive(Clone)]
pub struct B{}
impl Service for B {}

fn main()
{
    let mut objects: HashMap<String, Box<dyn Service>> = HashMap::new();
    objects.insert("test".to_string(), Box::new(A{}));
    objects.insert("test2".to_string(), Box::new(B{}));
    
    let v = Arc::new(objects);
    let o = Services{providers: v};
    
    for (key, _) in o.providers.iter() {
        println!("key: {} ", key);
    }
}

Upvotes: 0

Sean
Sean

Reputation: 3042

I'm afraid that's not gonna happened, if you look at the definition of Clone, it is required to Sized, but a trait object is not sized, you can't implement Clone for it.

you can wrap the provide in the Rc or Arc like this

#[derive(Clone)]
pub struct Services {
  providers: Arc<std::collections::HashMap<String, Box<dyn Service>>>
}

Upvotes: 2

Related Questions