Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does using Option::map to Box::new a trait object not work?

trait FooTrait {}

struct FooStruct;

impl FooTrait for FooStruct {}

fn main() {
    let maybe_struct: Option<dyn FooStruct> = None;

    //  Does not compile
    let maybe_trait: Option<Box<dyn FooTrait>> = maybe_struct.map(Box::new);

    // Compiles fine
    let maybe_trait: Option<Box<dyn FooTrait>> = match maybe_struct {
        Some(s) => Some(Box::new(s)),
        None => None,
    };
}
error[E0404]: expected trait, found struct `FooStruct`
 --> src/main.rs:9:34
  |
9 |     let maybe_struct: Option<dyn FooStruct> = None;
  |                                  ^^^^^^^^^ not a trait

Rustc 1.23.0. Why doesn't the first approach compile? Am I missing something obvious, or... huh?

like image 958
Tomáš Dvořák Avatar asked Feb 19 '18 10:02

Tomáš Dvořák


People also ask

How do you make a trait object in Rust?

We create a trait object by specifying some sort of pointer, such as a & reference or a Box<T> smart pointer, then the dyn keyword, and then specifying the relevant trait.

What is object safety in Rust?

Object Safety A trait is object safe if it has the following qualities (defined in RFC 255): All supertraits must also be object safe. Sized must not be a supertrait. In other words, it must not require Self: Sized . It must not have any associated constants.


1 Answers

Box::new only works with sized types; that is, it takes a value of a sized type T and returns Box<T>. In certain places a Box<T> can be coerced into a Box<U> (if T: Unsize<U>).

Such coercion does not happen in .map(Box::new), but does in Some(Box::new(s)); the latter is basically the same as Some(Box::new(s) as Box<FooTrait>).

You could create (in nightly) your own box constructor that returns boxes of unsized types like this:

#![feature(unsize)]

fn box_new_unsized<T, U>(v: T) -> Box<U>
where
    T: ::std::marker::Unsize<U>,
    U: ?Sized,
{
    Box::<T>::new(v)
}

and use it like .map(box_new_unsized). See Playground.

like image 180
Stefan Avatar answered Oct 07 '22 00:10

Stefan