Is it possible to pass a trait as a generic?

I am trying to compile this code:

pub struct AppWrap<Oid, StateT>
where
    Oid: Eq + std::hash::Hash + Clone,
{
    pub(crate) state: RefCell<Rc<dyn StateT>>,
}

I get this error:

  |
7 |     pub(crate) state: RefCell<Rc<dyn StateT>>,
  |                                      ^^^^^^ not a trait

Please ignore the fact that Oid is unused. I ripped out some parameters.

Question: is there some way to pass a trait as a Generic? If not, what are hacks to mimic this?

This should work:

pub struct AppWrap<Oid, StateT: ?Sized>
where
    Oid: Eq + std::hash::Hash + Clone,
{
    pub(crate) state: RefCell<Rc<StateT>>,
}

Why not make StateT be able to become a dyn Trait?

pub struct AppWrap<Oid, StateT: ?Sized>
where 
    Oid: Eq + std::hash::Hash + Clone,
{
    pub(crate) state: RefCell<Rc<StateT>>, // You sure you have your Rc/RefCell in the right order?
}
pub struct MyTest<StateT: ?Sized> {
    pub(crate) state: RefCell<Rc<dyn StateT>>,
}

still gets same error: "expected trait, found type parameter: StateT"

You should not have dyn in that location. It should be where you use MyTest instead e.g. MyTest<dyn MyTrait>.

1 Like

@alice This fixed it. Can you point me to dyn docs? (From Rust compiler errors, I have been adding dyn here and there, but apparently it's important to remove it here.)

In this particular weird case, I am after RefCell<Rc<T>> instead of Rc<RefCell<T>>. The result is because:

(1) with dyn, I generally end up using Rc<dyn T> anyway, and I need this inside a RefCell.

(2) there is a chance this ends up becoming a Rc<RefCell<Rc<dyn T>>>

I guess there is some documentation here. The reason you don't need dyn at that location is that StateT is a generic parameter, not a trait. It's just that traits are also types, and can also be put in generic locations as long as you allowed types that are not sized. There's no guarantee that the user will put a trait as the generic option — they could also put String or even non-sized concrete types such as [u8].

1 Like