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?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.