As far as I understand, the ownership of found_part is moved into the match_pair closure. Therefore it is no longer available in the next loop iteration.
Is there a way to fix this without inlining the closure?
Here is an alternative approach using a State struct, which should be a bit less performant due to Clone/Copy:
fn match_vectors(xs: &Vec<String>, ys: &Vec<String>) {
#[derive(Clone, Copy)]
struct State {
found_part: bool
}
fn match_pair(x: &str, y: &str, mut s: State) {
if y.starts_with(x) {
s.found_part = true;
}
}
let mut s = State {
found_part: false
};
for x in xs {
s.found_part = false;
for y in ys {
match_pair(x, y, s);
}
}
}
match_paircapturesfound_part by mutable reference. So while match_pair exists, it holds a unique mutable reference to found_part, which means you can't otherwise write to it, which you are attempting to do in your for x in xs loop.
What about making the closure stateless by returning the bool from it, rather than setting the found_part flag?
fn match_strings(xs: &[String], ys: &[String]) {
let match_pair = |x: &str, y: &str| {
y.starts_with(x)
};
for x in xs {
let mut found_part = false;
for y in ys {
found_part = match_pair(x, y);
}
}
}
Thanks! The production code has a bit more variables (see below). In principle returning a tuple of boolean variables would work here as well, although inlining the closure might be a bit simpler to understand.
fn match_strings(xs: &[String], ys: &[String]) -> bool {
let mut has_matched_x = vec![false; xs.len()];
let mut has_matched_y = vec![false; ys.len()];
let mut has_big_part = false;
let mut is_match = true;
let mut found_part = false;
let mut match_pair = |(x, i): (&str, usize), (y, j): (&str, usize)| {
if y.starts_with(x) && !has_matched_x[i] && !has_matched_y[j] {
has_matched_x[i] = true;
has_matched_y[j] = true;
found_part = true;
has_big_part |= x.len() > 1;
}
};
for (i, x) in xs.iter().enumerate() {
found_part = false;
for (j, y) in ys.iter().enumerate() {
match_pair((x, i), (y, j));
}
is_match = is_match && found_part;
}
is_match
}
If you would like to not restructure your code, then another option is to use std::cell::Cell<bool> in place of bool. That allows mutation through a non-exclusive borrow, so it avoids the conflict.