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.
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:
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.
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.)?