Trait Objects casting

Please see this example on the playground:

Specifically, the comments in get_obj()

It gets even more hairy in my real-world use case where I want to match on a user-supplied string and return any number of structs that implement a specific Trait. There's potential failure along the way and unwrapping a Result in order to re-wrap it is not ideal.

My workaround at the moment is different than here - rather I've just made the struct's new() return a Result<Box<dyn Trait>, Error> - but that's not wonderful.

Any insight and/or advice is appreciated. Thanks!

Casting from Box<Foo> to Box<dyn MyTrait> can be done with the as operator. You also need to use Option::map to perform the conversion on the content of Option:

fn get_obj() -> Option<Box<dyn MyTrait>> {
    Foo::new().map(|x| x as Box<dyn MyTrait>)
}

It is still odd that Foo::new returns a Box. It usually is better to just return a Foo (or maybe an Option<Foo> in this case). The called should decide whether to put the value in the box:

impl Foo {
    pub fn new() -> Option<Foo> {
        Some(Foo{
            name: String::from("Foo")
        })
    }
}

fn get_obj() -> Option<Box<dyn MyTrait>> {
    Foo::new().map(|x| Box::new(x) as Box<dyn MyTrait>)
}

Thanks! Why is that part necessary, i.e. why can't we just cast to Option<Box<dyn MyTrait>> without needing the Option.map ?

as can only perform type coercions and a specific set of casts (see reference for more information). Permitting a T as U conversion doesn't mean that Option<T> as Option<U> is also possible. There is no way to coerce or cast Option<T> to Option<U>, so a function call is needed for this operation.

2 Likes

Can you elaborate on that a bit more?

Or more generally - is there a good bullet list or article somewhere that explains more of like an intuition for when to reach for Box, and if you do need to reach for Box - where to do that (i.e. more nested, higher up, etc.)?

Specifically, there's this example: Returning different types in a match - #26 by dakom

Based on what you said, I would rather return Foo or Bar directly, not in a Box?