use std::marker::PhantomData;
trait SceneType {}
struct Scene<SceneType: ?Sized> {
_phantom: PhantomData<SceneType>
}
pub enum SceneOne {}
impl SceneType for SceneOne {}
impl<SceneOne> Scene<SceneOne> {
pub fn new() -> Self {
Self {
_phantom: Default::default()
}
}
}
fn main() {
let scene = Scene::<SceneOne>::new();
//works fine
//1 let boxed_scene: Box<Scene<dyn SceneType>> = Box::new(Scene::<SceneOne>::new());
// expected `Scene<dyn SceneType>`, found `Scene<SceneOne>` ... you could box the found value and coerce it to the trait object `Box<dyn SceneType>
//2 let boxed_scene: Box<Scene<dyn SceneType>> = Box::new(scene) as Box<Scene<dyn SceneType>>;
// as` expression can only be used to convert between primitive types or to coerce to a specific trait object
}
So the reason I ended up here is I wanted a new function to be generic over SceneType
and have common functions that operate on any scene with
impl<T: SceneType> Scene<T> {
...
My problem is I can't box these types to store them in a vector because of the listed error messages. The error for 2 makes sense but I am trying to coerce it to a specific trait type as far as I am aware.
You are running afoul of the very limited Unsized Coercion rules.
Coercion from sized to unsized, such as here from struct to trait, only work in a few limited cases, of interest here:
SceneOne
to dyn SceneType
.Foo<Type>
to Foo<Trait>
if:
Foo
.Foo
can itself be coerced to the appropriate unsized.So for example, if I define:
struct Scene<ST: ?Sized>(ST);
// OR
struct Scene<ST: ?Sized>(Box<ST>);
Then the unsized coercion will work since all the points are ticked.
On the other hand, with your definition:
struct Scene<ST: ?Sized>(PhantomData<ST>);
Then the unsized coercion from Scene<T>
to Scene<U>
is only possible if PhantomData<T>: Unsize<PhantomData<U>>
(point 3), and that is not the case. You can see it's not listed in the implemented traits.