Capture same variable in a closure in different ways

Hi, I have this block of code

query = query.bind((format!("select_{i}"), &selects[i]));

where query doesn't implement copy and bind() method takes ownership of self and return new type of Self
so if this make sense, when I put this block of code inside a closure like .for_each() or .map(), the query get captured by ownership, but what I want is capturing query by mutable reference so I can keep modifying the same query that I passed to the closure

this another example with the errors:

selects.iter()
	.enumerate()
	.map(|(i, select)| {
		query = query.bind((format!("select_{i}"), select));
		format!("type::field($relation_{i})")
	})
	.collect::<Vec<String>>()
	.join(",")
cannot move out of `query`, a captured variable in an `FnMut` closure
move occurs because `query` has type `surrealdb::method::Query<'_, surrealdb::engine::remote::ws::Client>`, which does not implement the `Copy` trait

it works If I did this:

let mut result = String::new();
for i in 0..selects.len() {
	query = query.bind((format!("select_{i}"), &selects[i]));
	result.push_str(&format!("type::field($relation_{i})"));
	if i != selects.len() - 1 {
		result.push(',')
	}
}
result

If query.bind requires ownership, capturing by mutable reference wouldn't work. I don't see a problem with using a for-loop, though I'd probably write something like this:

let mut strings = Vec::with_capacity(selects.len());

for (i, select) in selects.iter().enumerate() {
	query = query.bind((format!("select_{i}"), select));
	strings.push(format!("type::field($relation_{i})"));
}

let result = strings.join(",");

that's what I a summed as will, so iterators every were not ideal

If you need to change state beyond the iterator, for-loops are often easier than trying to use iterator combinators all the way. I assume you could do something weird with fold, storing query in the accumulator, but like I said, I prefer the good ol' for-loop in such scenarios.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.