How can I loop through a list of variables, potentially changing each one?

I'm working on a learning project, and I've got a bit where I want to modify the values of a certain set of variables. It's all the same code, so I wanted to make a list of these variables and then iterate through that list, operating on each. To explain, I made a minimal reproducer. The situation is like this:

fn add_ten_return_difference(n: &mut u32) -> u32 {
    *n += 10;
    20 - *n
}

fn main() {

    let mut var1 = 1;
    let mut var2 = 2;
    let mut other_thing = 0;

    other_thing += add_ten_return_difference(&mut var1);
    other_thing += add_ten_return_difference(&mut var2);

    println!("My numbers are now {} and {} and the other thing is {}",
              var1, var2, other_thing);
}

(This prints My numbers are now 11 and 12 and the other thing is 17, as expected.)

In the real code there are about a dozen variables which are structs rather than integers and the "other things" are more complicated, so it gets kind of crazy looking. Rather than have all of those duplicated lines, I want to loop through a list. This works for a read-only example:

fn just_return_difference(n: u32) -> u32 {
    10 - n
}


fn main() {

    let var1 = 1;
    let var2 = 2;
    let mut other_thing = 0;

    for n in [var1, var2].iter() {
        other_thing += just_return_difference(*n);
    }
    println!("My numbers are now {} and {} and the other thing is {}",
              var1, var2, other_thing);
}

(Prints My numbers are now 1 and 2 and the other thing is 17.)

... so I thought it'd be easy to make one where the vars are mutable. This leads to one of those rust-newbie situations where I'm fighting with the compiler.

I tried this:

 fn main() {

    let mut var1 = 1;
    let mut var2 = 2;
    let mut other_thing = 0;

    for mut n in [var1, var2].iter() {
        other_thing += add_ten_return_difference(&mut *n);
    }
    println!("My numbers are now {} and {} and the other thing is {}",
              var1, var2, other_thing);
}

… but that tells me cannot borrow *nas mutable, as it is behind a& reference, with the suggestion:

for mut n in [var1, var2].iter() {
    ----- help: consider changing this to be a mutable reference: `&mut u32`

… which then gets me

for &mut n in [var1, var2].iter() {
    ^^^^^^    ------------------- this expression has type `&{integer}`
    |
    types differ in mutability

So I thought oh, I see — duh and changed .iter() to .iter_mut(). But this tells me

type `{integer}` cannot be dereferenced.

I can change to for n in [var1, var2].iter_mut(), and now the code compiles, but n is only changed in the scope of the loop and var1 and var2 don't get altered.

Help me understand so I don't need to fight. :slight_smile: How should I be doing this?

You were on good track with iter_mut(): You should iterate through the list of references to variables:

for &mut var in [&mut var1, &mut var2].iter_mut() {
    other_thing += add_ten_return_difference(var);
}

Note that this loop is an iterator over Item=&mut &mut u32, that's why I've extracted one layer in the pattern (for &mut var).

1 Like

Ah, thanks! This gets me there. That should be:

for var in [&mut var1, &mut var2].iter_mut() {
  other_thing += add_ten_return_difference(var);
}

, right?

Yeah, this also works. It automatically derefs var: &mut &mut u32 to &mut u32 which is needed by add_ten_return_difference. More explicitely it would be:

add_ten_return_difference(*var)
1 Like

Huh. So in my actual code, I'm getting an error because var1 and var2 have different lifetimes. I can adjust the lifetime, but I'm concerned because the complaint is

but data from var2 flows into var1 here

on the for var in... line — and this happens even if I don't do anything at all in the body of the loop. What data is flowing in this situation?