Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested loops over an iterator inRust

In C, I can mutably iterate over an array in a nested fashion, using indices. In Rust, I can pretty much do the same using indices, but what if I want to use an iterator instead of indices?

The following piece of code for example compiles successfully since both borrows are immutable:

let xs = [0, 1, 2];
for x in &xs {
    for y in &xs {
        println!("x={} y={}", *x, *y);
    }
}

But what if I want to use a mutable iterator?

let mut xs = [0, 1, 2];
for x in &mut xs {
    *x += 1;
    for y in &mut xs {
        *y += 1;
        println!("x={} y={}", *x, *y);
    }
}

This results in:

error[E0499]: cannot borrow `xs` as mutable more than once at a time

I understand the need to channel write access to data, but I also wonder how an experienced Rust user would achieve that using only iterators -- let's say indices are out of the picture just for educational purposes.

like image 237
qwe Avatar asked Aug 09 '26 14:08

qwe


1 Answers

I understand the need to channel write access to data, but I also wonder how an experienced Rust user would achieve that using only iterators

They would not because it's not feasible, at least not as-is: while desugaring to while let is a common method, it'd be for nesting loops where you want to advance the same iterator in the outer and inner loop, it avoids the need for an exclusive borrow spanning the entire loop.

Here though, you don't want to advance the same iterator in different places, instead you want two different mutating iterators to the same collection. Meaning you have two different mutable references to the same collection (which is not allowed) and you would eventually have two mutable references to the same item of a collection (which is also not allowed).

At best, you could use interior mutability to resolve the issue e.g.

let xs = [Cell::new(0), Cell::new(1), Cell::new(2)];
for x in &xs {
    x.set(x.get() + 1);
    for y in &xs {
        y.set(y.get() + 1);
        println!("x={} y={}", x.get(), y.get());
    }
}

but I don't think that would be the usual choice (falling back to indices would be, as it would not require changing the data itself).

like image 105
Masklinn Avatar answered Aug 12 '26 03:08

Masklinn