21

In C++, I could put an array of 1000 ints onto the heap like this:

int size = 1000;
int* values = new int[size];
delete[] values;

I can't figure out how to do the equivalent in Rust.

let size = 1000;
let values = Box::new([0; size]) // error: non-constant path in constant expression

To my understanding, Rust forces the size of all arrays to be known at compile time and doesn't let you use expressions when creating arrays.

trincot
  • 317,000
  • 35
  • 244
  • 286
Brady Dean
  • 3,378
  • 5
  • 24
  • 50
  • See also [Creating a fixed-size array on heap in Rust](http://stackoverflow.com/q/25805174/155423), [How to allocate arrays on the heap in Rust 1.0 (beta)?](http://stackoverflow.com/q/30242770/155423) or [*The Rust Programming Language* chapter on vectors](https://doc.rust-lang.org/stable/book/vectors.html). I'd **highly recommend reading the book** as it covers *many* of these introductory topics. – Shepmaster Jan 18 '17 at 13:53

3 Answers3

41

Arrays in Rust are fixed-length. If you want a dynamically-sized array, use Vec. In this case, the simplest way is with the vec! macro:

let size = 1000;
let values = vec![0; size];

Also, if you're super concerned about Vec being three words long and don't need to resize the storage after it's created, you can explicitly discard the internal capacity, and bring values down to two words on the stack:

let values = values.into_boxed_slice(); // returns a Box<[i32]>.
DK.
  • 55,277
  • 5
  • 189
  • 162
  • How did you figure out the default sizes of a Vec vs a Box? – Sharpiro Sep 19 '19 at 21:20
  • 3
    A (boxed) slice just stores a pointer to the start of the slice and the length of the slice as a pointer-sized integer. A `Vec` is a *growable* array, so it allocates extra space for additional elements. This means that a `Vec` also has to store the capacity of the allocated buffer (which is at least as large as the length). (So think of a `Box<[_]>` as 2 pointers and a `Vec<_>` as 3.) – csander May 28 '20 at 17:02
3

Rust's heap allocated array is the std::Vec. Under the hood it is just an array (Read §Guarantees in the doc: https://doc.rust-lang.org/std/vec/struct.Vec.html#guarantees)

To allocate uninitialized memory use Vec::with_capacity(). Then push() values as needed:

// preallocate the vector capacity
let mut values = Vec::<i32>::with_capacity(1000);

// fill the vector with values
for i in 0..1000 {
    values.push(i);
}

// downgrade into a boxed slice
let mut values = values.into_boxed_slice();
drzymala
  • 2,009
  • 20
  • 26
  • However, it's not possible to "set" a value into i-th position of the `Vec`, as it's possible do with an array, right? – yegor256 Apr 23 '23 at 06:58
  • 1
    @yegor256 it is totally possible. Use `get_mut` to get a mutable reference to the index you want and then modify it in place. – drzymala Apr 24 '23 at 16:14
-3

In case that the size of the array can be determined at compile time*, you can use a constant like this:

const size: usize = 1000; // or: = some_const_fn() 
let values = Box::new([0; size])

* Since Rust 1.46 control flows and loops are supported in const fn.

Daniel
  • 1,358
  • 11
  • 15
  • 1
    As of this post date, and using version `rustc 1.56.0-nightly (0035d9dce 2021-08-16)`, this actually initializes on the stack, not the heap. You can find out by increasing the size to some huge value that the stack can't hold. Of course, interestingly enough, it only stack overflows on a debug build, but works on a release build. – Kobato Sep 17 '21 at 21:35
  • 3
    Yes, it first initializes the array on the stack, then moves it into the heap. Until [`box` syntax](https://doc.rust-lang.org/beta/unstable-book/language-features/box-syntax.html) is stabilized, AFAIK there's no way to initialize a variable directly on the heap. – Daniel Sep 18 '21 at 17:07
  • It would be nice to finally see a fix for this, that way we don't have to use a vec and `.into_boxed_slice()` as a workaround (and the different behavior between debug/release builds that honestly shouldn't even be happening) – Kobato Sep 18 '21 at 17:36