1

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]);
}
Boiethios
  • 38,438
  • 19
  • 134
  • 183

2 Answers2

6

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();
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Is `::::` not type ascription? – Boiethios Jul 17 '17 at 13:59
  • @Boiethios no, that's a separate feature that is not stabilized. – Shepmaster Jul 17 '17 at 14:04
  • About the last line, I tried to use the opposite: https://doc.rust-lang.org/std/primitive.slice.html#method.into_vec with an empty slice, *e.g.*: `Box::<[i32]>::new([]).into_vec()` – Boiethios Jul 17 '17 at 14:08
  • 2
    Just a terminological point: it seems to be an unsizing coercion and not a `Deref` coercion. – Masaki Hara Jul 17 '17 at 14:11
  • @MasakiHara thank you! I always screw up the various coercions. – Shepmaster Jul 17 '17 at 14:20
  • 1
    @Shepmaster, `as` casts are [superset of coercions](https://doc.rust-lang.org/nomicon/casts.html) and `Box<[T; N]>` can be coerced to `Box<[T]>` because `[T; N]` is `Unsize<[T]>` ([Unsize trait](https://doc.rust-lang.org/std/marker/trait.Unsize.html)) and there exists blanket implementation [`impl, U> CoerceUnsized> for Box`](https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html) – red75prime Jul 17 '17 at 14:22
  • Anyway, for now it can be described as compiler magic. [DST coercion RFC](https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md) isn't stable yet. – red75prime Jul 17 '17 at 14:34
2

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.

ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • 1
    I was going to answer similarly, but OP is likely just misusing the term "type ascription". They really just mean to use a turbofish. They also want to have a `Box<[i32]>`, not a `Box<[i32; 2]>` — these are different types. – Shepmaster Jul 17 '17 at 13:50
  • @Shepmaster in that case I don't know if it's possible :) - especially if you want a boxed slice without a specific length. – ljedrz Jul 17 '17 at 13:52
  • Hum, I think I understand now from your comments. – Boiethios Jul 17 '17 at 13:54