TomZz
TomZz

Reputation: 101

How can I repeatedly borrow the variable outside the closure in different closures in Rust?

This is the core codes, which return the type of Vec<(&'a str, i32)> When I run this code,

let mut i = 0;
contents.lines().filter(|x| {
    i += 1;
    x.to_lowercase().contains(&query.to_lowercase())
}).map(|x|
    (x, i)
).collect()

it alerts that:

contents.lines().filter(|x| {
   |                             --- mutable borrow occurs here
56 |         i += 1;
   |         - first borrow occurs due to use of `i` in closure
57 |         x.to_lowercase().contains(&query.to_lowercase())
58 |     }).map(|x|
   |        --- ^^^ immutable borrow occurs here
   |        |
   |        mutable borrow later used by call
59 |         (x, i)
   |             - second borrow occurs due to use of `i` in closure

So how can I correct this code?

Upvotes: 0

Views: 100

Answers (2)

TomZz
TomZz

Reputation: 101

@Chayim Friedman Thanks for your tips! Now I could use the filter_map method to achieve my own aim and has learnt a skilled way to use the zip.

    let mut i = 0;
    contents.lines().filter_map(|x| {
        i += 1;
        if x.to_lowercase().contains(&query.to_lowercase()) {
            Some((x, i))
        } else {
            None
        }
    }).collect() 

Upvotes: 1

Chayim Friedman
Chayim Friedman

Reputation: 70860

The best way to fix this code is to realize that what you're doing is essentially enumerate() with index starting from 1 instead of zero, so either:

contents.lines().enumerate().filter(|(_, x)| {
    x.to_lowercase().contains(&query.to_lowercase())
}).map(|(i, x)|
    (x, i + 1)
).collect()

Or:

contents.lines().zip(1..).filter(|(x, _)| {
    x.to_lowercase().contains(&query.to_lowercase())
}).collect()

Upvotes: 1

Related Questions