Reputation: 2841
trait MyTrait {
fn foo(&self);
}
struct A {}
impl MyTrait for A {
fn foo(&self) {
println!("A");
}
}
struct B {}
impl MyTrait for B{
fn foo(&self) {
println!("B");
}
}
enum MyEnum {
A,
B,
}
fn create_object(my_enum: MyEnum) -> Box<dyn MyTrait> {
let boxed_value: Box<dyn MyTrait> = match my_enum {
MyEnum::A => Box::new(A{}),
MyEnum::B => Box::new(B{}),
};
boxed_value
}
struct C<Allocator>
where Allocator: MyTrait + ?Sized {
a: Box<Allocator>,
}
impl<Allocator> C<Allocator>
where Allocator: MyTrait {
pub fn new(a: Box<Allocator>) -> Self {
Self {a: a}
}
}
fn main() {
let boxed_value = create_object(MyEnum::A);
C::new(boxed_value);
}
compile error:
Compiling playground v0.0.1 (/playground)
error[E0277]: the size for values of type `dyn MyTrait` cannot be known at compilation time
--> src/main.rs:49:12
|
49 | C::new(boxed_value);
| ------ ^^^^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn MyTrait`
note: required by a bound in `C::<Allocator>::new`
--> src/main.rs:39:6
|
39 | impl<Allocator> C<Allocator>
| ^^^^^^^^^ required by this bound in `C::<Allocator>::new`
40 | where Allocator: MyTrait {
41 | pub fn new(a: Box<Allocator>) -> Self {
| --- required by a bound in this associated function
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to previous error
I am not sure what this means. Trait object doesn't have a fixed size. The boxed object wraps the trait object, so it has a fixed size. How to modify this code? I have to dynamically generate boxed trait object on demand.
Upvotes: 0
Views: 190
Reputation: 16925
The type of boxed_value
in main()
is Box<dyn MyTrait>
, which is a fat pointer because of dyn
.
But C::new()
expects a Box<Allocator>
where Allocator
is a concrete type (implementing MyTrait
), i.e. a normal pointer (not fat) because no virtual-table is needed here.
Even if a Box<dyn MyTrait>
actually points toward a A
, it is not the same type as Box<A>
.
Moreover, you cannot go back from a dyn
type to a concrete type (except by downcasting with Any
, which implies a runtime check).
I think you could simply use dyn MyTrait
all along the way in C
.
struct C {
a: Box<dyn MyTrait>,
}
impl C {
pub fn new(a: Box<dyn MyTrait>) -> Self {
Self { a }
}
}
I probably misunderstood the intention behind C
.
I thought the (dynamic) polymorphism relied only on boxed_value
but if another level of (static) polymorphism is also needed on C
, then the original code with + ?Sized
in the implementation is probably much better (as stated in the comments).
(I let this answer visible in case it corresponds to the intended usage; I will delete it if the author of the question confirms that I'm totally wrong.)
Upvotes: 0