Reputation: 93
I'm fairly new to Rust, I was tying to implement a struct that could have different structs that implemented a common trait as a field
In traditional programming languages with garbage collector I would have implemented it like this:
pub struct MemoryMapper {
regions: Vec<Region>,
}
trait MemoryMappable: Sized {
}
pub struct Region {
device: dyn MemoryMappable,
start: u32,
end: u32,
remap: bool
}
But here I have the following compilation error:
the size for values of type `(dyn MemoryMappable + 'static)` cannot be known at compilation time
the trait `Sized` is not implemented for `(dyn MemoryMappable + 'static)`
only the last field of a struct may have a dynamically sized type
change the field's type to have a statically known size
I have tried making Sized a supertrait of MemoryMappable, but it still gives me issues with the following code:
pub fn map(&mut self, device: dyn MemoryMappable, start: u32, end: u32, remap: bool) -> &Region {
self.regions.insert(0, Region{device, start, end, remap});
return self.regions.get(0).unwrap();
}
the trait `MemoryMappable` cannot be made into an object
`MemoryMappable` cannot be made into an object
Because from Rust documentation about object safety
Sized must not be a supertrait. In other words, it must not require Self: Sized.
I have no idea of how to go about this at this point
Upvotes: 3
Views: 876
Reputation: 10156
Fields of Sized
structs can exist on the stack, and so must have a known size at compile time. This is what the Sized
error is saying.
dyn Trait
is "any type that implements Trait
. So what is its size? Well, it depends on what the underlying type is.
Therefore, dyn Trait
never implements Sized
, even if Trait
has Sized
as a supertrait (all this does is guarantee that any type that implements Trait
also implements Sized
, but you still don't know which one it is).
In fact, making Sized
a supertrait of Trait
is how you opt-out of object safety, which makes it impossible to construct a dyn Trait
.
Instead, the way you get around this is by using a pointer-like type:
Box<dyn Trait>
creates an owned pointer&dyn Trait
creates a referenceArc<dyn Trait>
creates a reference counted pointerThe choice of pointer type depends on your use case, but in most scenarios, Box<dyn Trait>
is fine, and is a good starting point.
Upvotes: 3