14

Editor's note: this question was asked before Rust 1.0 and some of the assertions in the question are not necessarily true in Rust 1.0. Some answers have been updated to address both versions.

I want to create a vector, but I only know the size I want the vector to be at runtime. This is how I'm doing it now (i.e. creating an empty, mutable vector, and adding vectors to it) :

fn add_pairs(pairs: ~[int]) -> ~[int] {
    let mut result : ~[int] = ~[];
    let mut i = 0;
    while i < pairs.len() {
        result += ~[pairs[i] + pairs[i + 1]];
        i += 2;
    }
    return result;
}

This is how I want to do it (i.e., creating a vector and putting everything in it, instead of adding lots of vectors together):

fn add_pairs(pairs: ~[int]) -> ~[int] {
    let number_of_pairs = pairs.len() / 2;
    let result : ~[int, ..number_of_pairs];
    let mut i = 0;
    while i < pairs.len() {
        result[i] = pairs[2 * i] + pairs[2 * i + 1];
        i += 1;
    }
    return result;
}

Unfortunately, doing the above gives me something like:

error: expected constant expr for vector length: Non-constant path in constant expr
let result: ~[int, ..number_of_pairs];
             ^~~~~~~~~~~~~~~~~~~~~~~~

I get the impression that vectors have to have their size known at compile time (and so you need to set their size to a constant). Coming from a Java background, I'm confused! Is there a way to create a vector whose size you only know at runtime?

I'm using Rust 0.6.

Boiethios
  • 38,438
  • 19
  • 134
  • 183
Daniel
  • 10,115
  • 3
  • 44
  • 62
  • 2
    This was a good questinon but is now pretty obsolete given all the changes from Rust 0.6 to 1.0... – poolie Aug 09 '15 at 16:56
  • This code is barely recognisable as Rust any more. Unlike many other pre-1.0 questions, this one's virtually useless nowadays. – wizzwizz4 Jun 27 '19 at 08:42

3 Answers3

16

In Rust version 1.0.0, they've made the std::vec:Vec public structure stable so that you can instantiate a growable vector with let mut my_vec = Vec::new(); You can also use the vec! macro like so: let mut another_vec = vec![1isize, 2isize, 3isize]; What is important to note is that in both cases the variable you're assigning must be mutable.

With these vectors you can call my_vec.push(num); for individual items or another_vec.extend_from_slice(["list", "of", "objects"]); to add items to the end of the vector.

For your specific problem, you could do something like this:

fn add_pairs(pairs: Vec<(Vec<isize>)>) -> Vec<isize> {
    let mut result = Vec::new();
    for pair in pairs.iter() {
        result.push(pair[0]);
        result.push(pair[1]);
    }
    return result;
}

You can see this in action on the Rust Playground where you have (what I assumed) was a nested vector of integer pairs.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
rouma7
  • 566
  • 6
  • 8
12

There is no way to create an array of constant length with the length determined at runtime; only compile-time constant length arrays are allowed, so (variations of) your first method with Vec<i32> (previously ~[int]) is the only supported way. You could use vec![0; number_of_pairs] to create a vector of the correct size and use the second part.


There are many helper functions for what you are trying to do (using while directly Rust should be very rare):

fn add_pairs(pairs: &[i32]) -> Vec<i32> {
    let mut result = Vec::new();
    for i in 0..(pairs.len() / 2) {
        result.push(pairs[2 * i] + pairs[2 * i + 1])
    }
    result
}

Or even

fn add_pairs(pairs: &[i32]) -> Vec<i32> {
    pairs
        .chunks(2)
        .filter(|x| x.len() == 2)
        .map(|x| x[0] + x[1])
        .collect()
}

Docs: chunks, filter, map, collect. (The filter is just because the last element of chunks may have length 1.)

Also note that adding two vectors allocates a whole new one, while push doesn't do this necessarily and is much faster (and .collect is similar).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
huon
  • 94,605
  • 21
  • 231
  • 225
  • Thanks for the syntax suggestions too: I'm still struggling with the docs! – Daniel May 25 '13 at 05:00
  • Everyone is :) it's one of the biggest problems with Rust at the moment. (Other places to ask questions about Rust are the [IRC](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust) channel and the [mailing list](https://mail.mozilla.org/listinfo/rust-dev), they almost always have someone willing to help.) – huon May 25 '13 at 05:19
  • It's worth noting you can now use `.chunks_exact()` instead of combining `chunks` and `filter` to enforce equally sized chunks. – Noah May Apr 29 '23 at 22:51
2

In at least Rust 1.0, there is a Vec::with_capacity() function that handles this scenario.

Example code:

let n = 44; // pretend this is determined at run time
let mut v = Vec::<f64>::with_capacity(n);
v.push(6.26);
println!("{:?}", v);            // prints [6.26]
println!("{:?}", v.len());      // prints 1
println!("{:?}", v.capacity()); // prints 44
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
quux00
  • 13,679
  • 10
  • 57
  • 69
  • 2
    `with_capacity` is slightly different: it just allocates that much backing storage, it doesn't fill the vector with elements. – huon Feb 04 '14 at 09:44