0
votes

I am trying to store a reference to a trait in a second struct. The trait is supposed to implement a more high level trait that I want to use to call functions on the specialized trait.

How can I tell Rust that my trait T, inside the Box implements the trait that I want to call, even though it is a composed trait?

I also tried

impl<T: 'static> Storage<T>
where
T: DerefMut<Target=dyn ToBeCalled>,
{

I then have 2 Dyn traits that are not the same and I can't find a way to cast them. It probably causes problems with how to handle vtables internally in rust.


I have the following code in my program (spread around a few structs & traits, but this snippet results in the same compiler error).

use core::ops::DerefMut;

pub trait ToBeCalled {
    fn to_call(&mut self);
}
pub trait MoreAdvanced : ToBeCalled
{
    fn something_else(&mut self);
}

struct MoreAdvancedImpl
{
}

impl MoreAdvanced for MoreAdvancedImpl
{
    fn something_else(&mut self) {}
}

impl ToBeCalled for MoreAdvancedImpl
{
    fn to_call(&mut self) {}
}

pub struct Storage<T> {
    pub store: T,
}

impl<T: 'static, U> Storage<T>
where
T: DerefMut<Target=U>,
U: ToBeCalled, //Why must U be sized here?
{
    pub fn new(store: T) -> Self {
        Storage {
            store,
        }
    }
    pub fn call_high_level_function(&mut self)
    {
        self.store.to_call();
    }
}

fn main()
{
    let mai = MoreAdvancedImpl{};
    let a : Box<dyn MoreAdvanced> = Box::new(mai);
    //let a = Box::new(mai); // This works, but here the size is not "hidden" by the trait
    let _b = Storage::new(a);
}

Compile output:

error[E0277]: the size for values of type `dyn MoreAdvanced` cannot be known at compilation time
  --> src/main.rs:46:27
   |
20 |     pub fn new(store: T) -> Self {
   |     ---------------------------- required by `Storage::<T>::new`
...
46 |     let _b = Storage::new(a);
   |                           ^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn MoreAdvanced`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
2

2 Answers

3
votes

Sized is implied by default. To opt-out of this behavior you can use ?Sized. The Rust docs mention:

All type parameters have an implicit bound of Sized. The special syntax ?Sized can be used to remove this bound if it's not appropriate.

There's a bit more information on this in the Rust Book:

0
votes

For others who want it spelled out clearly like me (see comment to the answer above): Change:

impl<T: 'static, U> Storage<T>
where
T: DerefMut<Target=U>,
U: ToBeCalled, //Why must U be sized here?
{

to

impl<T: 'static, U: ?Sized > Storage<T>
where
T: DerefMut<Target=U>,
U: ToBeCalled, 
{