3

Pretty new to Rust, decided to brush up using the Advent of Code 2020 Day 1 Puzzle. I'm using the following function:

fn find_numbers_2020(v: Vec<i32>) -> (i32,i32) {
    let mut n1: i32 = 0;
    let mut n2: i32 = 0;
    let mut cnt = 0;
    let size = v.len();
    for v_i in v {
        n1 = v_i;
        cnt = cnt+1;
        for i in cnt..size {
            if (n1 + *v.get(i).unwrap()) == 2020 {
                n2 = *v.get(i).unwrap();
                (n1, n2) //Issue is here
            }
        }
    }
    (n1, n2)
 }

But I get the error "32 (n1, n2)

     ^^^^^^^^ expected (), found tuple.

It's being called from main as follows

fn main() {
     let filename = String::from("./input.txt");
     let v = parse_file(filename); //This works fine
     for v_i in v {
          println!("{}", v_i);
     }
     let result = find_numbers_2020(v);
     let (n1, n2) = result;
     println!("{} + {} = {}", n1, n2, n1+n2);
     println!("{} * {} = {}", n1, n2, n1*n2);
}

I should also mention that v is a Vec<i32>. Sorry for the beginner question but Rust can be a little confusing and I haven't been able to find any answers through googling.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197

2 Answers2

1

You can omit the return keyword only if the returned value is the last expression in the function block, otherwise you need to explicitly use return. Adding return to your example fixes that particular error but a bunch of new ones come up in its place. This is how I'd write the function:

fn find_numbers_2020(v: Vec<i32>) -> (i32, i32) {
    for (skip, &n1) in v.iter().enumerate() {
        for &n2 in v.iter().skip(skip) {
            if n1 + n2 == 2020 {
                return (n1, n2);
            }
        }
    }

    panic!("no pair of numbers in vec sum to 2020");
}
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
1

This is one of those cases where you need to use a return expression. Your initial for loop also consumes v, so to be able to do v.get() in the inner loop, you need to borrow v instead, i.e. &v or v.iter().

fn find_numbers_2020(v: Vec<i32>) -> (i32, i32) {
    let mut n1: i32 = 0;
    let mut n2: i32 = 0;
    let mut cnt = 0;
    let size = v.len();
    for &v_i in &v {
        n1 = v_i;
        cnt = cnt + 1;
        for i in cnt..size {
            if (n1 + *v.get(i).unwrap()) == 2020 {
                n2 = *v.get(i).unwrap();
                return (n1, n2);
            }
        }
    }
    (n1, n2)
}

This is also a perfect case of when you could return an Option and use an if let expression. So instead of returning (i32, i32) then you would return Option<(i32, i32)>.

Instead of doing *v.get(i).unwrap(), then you can also just index v, i.e. v[i].

fn find_numbers_2020(v: Vec<i32>) -> Option<(i32, i32)> {
    let mut cnt = 0;
    for &n1 in &v {
        cnt += 1;
        for i in cnt..v.len() {
            if (n1 + v[i]) == 2020 {
                let n2 = v[i];
                return Some((n1, n2));
            }
        }
    }
    None
}

fn main() {
    // ...

    if let Some((n1, n2)) = result {
        println!("{} + {} = {}", n1, n2, n1 + n2);
        println!("{} * {} = {}", n1, n2, n1 * n2);
    }
}

Instead of manually incrementing indices, you can use enumerate() in the first loop, then in the second loop you can use skip(i + 1) with the index returned by enumerate().

fn find_numbers_2020(v: Vec<i32>) -> Option<(i32, i32)> {
    for (i, &n1) in v.iter().enumerate() {
        for &n2 in v.iter().skip(i + 1) {
            if (n1 + n2) == 2020 {
                return Some((n1, n2));
            }
        }
    }
    None
}

Instead of v: Vec<i32>, it would be more idiomatic to use a slice, i.e. v: &[i32]. In main() you just have to borrow v in your find_numbers_2020() call, i.e. find_numbers_2020(&v)

vallentin
  • 23,478
  • 6
  • 59
  • 81