Trait Objects casting


#1

Please see this example on the playground:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=3dcb047fa3026b54dd90142a933cb00e

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!


#2

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>)
}

#3

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


#4

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.