admin管理员组

文章数量:1430490

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
}

Playground link

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.

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
}

Playground link

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.

Share Improve this question edited Nov 19, 2024 at 16:20 kmdreko 62.1k6 gold badges95 silver badges164 bronze badges asked Nov 19, 2024 at 13:59 C. DowC. Dow 855 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 6

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:

  • Type to trait, thus SceneOne to dyn SceneType.
  • Foo<Type> to Foo<Trait> if:
    1. The type implements the trait.
    2. The type parameter only appears once in the last field Foo.
    3. The last field of 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.

本文标签: rustWhy is this MyStructltTgt not coercing properly into MyStructltdyn TgtStack Overflow