Boiethios
Boiethios

Reputation: 42829

How to create a boxed slice without using type ascription?

It is easy to create a boxed slice:

fn main() {
    let _ = Box::new([42, 0]);
}

But if I want to add specify a type:

fn main() {
    let _ = Box::<[i32]>::new([42, 0]);
}

I get:

error: no associated item named `new` found for type `std::boxed::Box<[i32]>` in the current scope
  --> src/main.rs:2:13
   |
 2 |     let _ = Box::<[i32]>::new([42, 0]);
   |             ^^^^^^^^^^^^^^^^^
   |
   = note: the method `new` exists but the following trait bounds were not satisfied: `[i32] : std::marker::Sized`

This is really strange, because it works with type ascription:

fn main() {
    let _: Box<[i32]> = Box::new([42, 0]);
}

Upvotes: 1

Views: 3362

Answers (2)

Shepmaster
Shepmaster

Reputation: 431619

It is easy to create a boxed slice

Except you didn't do that. If you print the type, you can see that Box::new([1, 2]) creates a boxed array, not a slice. On the other hand, let _: Box<[i32]> = Box::new([1, 2]) creates a boxed array and the converts it to a boxed slice. These have different types. Notably, the first type has a length known at compile time, the second no longer does.

You can use as as well:

fn main() {
    let _ = Box::new([1, 2]) as Box<[i32]>;
}

Box::<[i32]>::new([1, 2]) doesn't work for the reason the error message says: T is not Sized. T is directly mapped to the type being boxed.

Box::new([1, 2]) as Box<[i32]> works because a sized item is passed to Box::new and then it is converted to a type with an unsized inner bit using unsized coercions.

It appears that unsized coercions don't apply for actual type ascription, an unstable feature in nightly Rust:

#![feature(type_ascription)]

fn main() {
    let foo = Box::new([1, 2]): Box<[i32]>;
}

For this specific case, you can use into_boxed_slice, which should avoid the need for any stack allocation.

vec![1, 2].into_boxed_slice();

Upvotes: 6

ljedrz
ljedrz

Reputation: 22273

This is an experimental feature:

#![feature(type_ascription)]

fn main() {
    let _ = Box::new([42, 0]: [i32; 2]);
}

Also, in that case you need to be explicit about the length.

Upvotes: 2

Related Questions