List the combinations that add up to 0 from a vector of numbers I'm writing a function that, given a Vec&lt;i32&gt; of numbers, lists the combinations that add up to 0. The code works, but it feels amateurish.

Specifically, the inside of the loop looks really ugly -- there must be a simpler way of doing this that avoids unwrap() and the repetition. Maybe with match?

fn calc_zer(input: Vec&lt;i32&gt;) -&gt; Vec&lt;(i32, i32, i32)&gt; {
    let mut output: Vec&lt;(i32, i32, i32)&gt; = Vec::new();
    for a in (0..input.len() - 2) {
        for b in (a+1..input.len() -1) {
            for c in (b+1..input.len()) {
                if (input.get(a).unwrap() + input.get(b).unwrap() + input.get(c).unwrap() == 0) {
                    output.push((*input.get(a).unwrap(), *input.get(b).unwrap(), *input.get(c).unwrap()));
                }
            }
        }
    }
    output
}
Rust is a statically-compiled language, which means you get warnings and errors at compile time. Don't ignore those:

warning: unnecessary parentheses around `for` head expression
 --&gt; src/main.rs:3:14
  |
3 |     for a in (0..input.len() - 2) {
  |              ^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_parens)] on by default

warning: unnecessary parentheses around `for` head expression
 --&gt; src/main.rs:4:18
  |
4 |         for b in (a+1..input.len() -1) {
  |                  ^^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_parens)] on by default

warning: unnecessary parentheses around `for` head expression
 --&gt; src/main.rs:5:22
  |
5 |             for c in (b+1..input.len()) {
  |                      ^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_parens)] on by default

warning: unnecessary parentheses around `if` condition
 --&gt; src/main.rs:6:20
  |
6 |                 if (input.get(a).unwrap() + input.get(b).unwrap() + input.get(c).unwrap() == 0) {
  |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_parens)] on by default

Next, run Clippy to get even more automated suggestions. Note that this contains the answer to your question:

warning: this argument is passed by value, but not consumed in the function body
 --&gt; src/main.rs:1:24
  |
1 | pub fn calc_zer(input: Vec&lt;i32&gt;) -&gt; Vec&lt;(i32, i32, i32)&gt; {
  |                        ^^^^^^^^ help: consider changing the type to `&amp;[i32]`
  |
  = note: #[warn(needless_pass_by_value)] on by default
  = help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_pass_by_value

warning: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
 --&gt; src/main.rs:6:20
  |
6 |                 if input.get(a).unwrap() + input.get(b).unwrap() + input.get(c).unwrap() == 0 {
  |                    ^^^^^^^^^^^^^^^^^^^^^ help: try this `&amp;input[a]`
  |
  = note: #[warn(get_unwrap)] on by default
  = help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#get_unwrap

Extract local variables so you don't even have the overhead of accessing the array multiple times.
There's no reason to provide an explicit type for output - it will be inferred from the return value.
Extract a variable for input.len() since that never changes during the iteration.
It's almost always better to iterate over the collection directly instead of indexing it. We can also use Iterator::enumerate to get the index as we go along.


This yields

fn calc_zer(input: &amp;[i32]) -&gt; Vec&lt;(i32, i32, i32)&gt; {
    let mut output = Vec::new();

    let len = input.len();

    for (a_i, &amp;a) in input[0..len - 2].iter().enumerate() {
        for (b_i, &amp;b) in input[a_i + 1..len - 1].iter().enumerate() {
            for &amp;c in &amp;input[a_i + b_i + 2..len] {
                if a + b + c == 0 {
                    output.push((a, b, c));
                }
            }
        }
    }

    output
}


This is a bit ugly, and even worse — I got it wrong originally! See the revision history for details. This was caused because enumerate starts counting from zero, even though we are iterating through an offset into the original vector. 

However, Rust has a strong emphasis on reusing code via crates. In this example, I turn to one of my favorites — itertools:

extern crate itertools;

use itertools::Itertools;

fn calc_zer(input: &amp;[i32]) -&gt; Vec&lt;(i32, i32, i32)&gt; {
    input.iter()
        .tuple_combinations()
        .filter(|&amp;(a, b, c)| a + b + c == 0)
        .map(|(&amp;a, &amp;b, &amp;c)| (a, b, c))
        .collect()
}


Much more readable!