3

I am trying to give a static method reference and type argument for Box::new and could not manage to compile it.

I have the following structure:

trait MyTrait {
    fn hello(&self);
}

struct MyStruct;

impl MyTrait for MyStruct {
    fn hello(&self) {
        println!("Hello");
    }
}

In my main method, I want to cast these structs to trait objects, put them in a Box, and return it as a vector. I have managed to do it this way:

fn main() {
    let my_vec = vec![MyStruct];

    let my_trait_vec: Vec<Box<MyTrait>> = my_vec
        .into_iter()
        .map(|x| {
            let boxed: Box<MyTrait> = Box::new(x);
            boxed
        })
        .collect();
}

I am looking for something like :

let mut my_trait_vec: Vec<Box<MyTrait>> = my_vec.into_iter().map(Box::new::<MyTrait>).collect();

This is not accepted by the compiler and it complains about an unexpected type argument for Box::new().

Is it possible to make this boxing operation in a single line without declaring any external function?

Playground

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Akiner Alkan
  • 6,145
  • 3
  • 32
  • 68
  • `Box::::new` make more sense but doesn't compile. I don't really understand why – Stargateur Mar 29 '19 at 12:30
  • 1
    See also [How does the mechanism behind the creation of boxed traits work?](https://stackoverflow.com/q/52288980/155423); [How can I box the contents of an iterator of a type that implements a trait?](https://stackoverflow.com/q/48180008/155423) – Shepmaster Mar 30 '19 at 15:10

1 Answers1

4

Since you want to give a type parameter to the Box type, the correct syntax would be Box::<dyn MyTrait>::new rather than Box::new::<dyn MyTrait>. However, this won't work either, since the compiler would try to coerce the type of the argument to Box::new() to dyn MyTrait before passing it by value, which is not possible for dynamically sized types. You need to create the box first, and only then can you perform the unsized coercion, so the code you have is fine. Here is an alternative that is essentially the same, just written a bit more concisely:

let mut my_trait_vec: Vec<Box<dyn MyTrait>> = my_vec
    .into_iter()
    .map(|x| Box::new(x) as Box<dyn MyTrait>)
    .collect();

Yet another option is to define a helper function, e.g.

fn into_boxed_trait<T>(value: T) -> Box<dyn MyTrait>
where
    T: MyTrait + 'static,
{
    Box::new(value)
}

This will allow you to write

let mut my_trait_vec: Vec<_> = my_vec
    .into_iter()
    .map(into_boxed_trait)
    .collect();
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841