Guess what? I also have a borrowing problem

When trying to solve another question asked here, I came across this problem:
I am trying to get the intersection of HashSets.
With

let mut common_binaries: Box<dyn Iterator<Item = &str>> =
    Box::new(binaries.pop().unwrap().into_iter());
    
for current_set in binaries {
    common_binaries = Box::new(common_binaries.filter(|it| current_set.contains(*it)));
}

I get:

error[E0597]: `current_set` does not live long enough
  --> src/main.rs:22:64
   |
22 |         common_binaries = Box::new(common_binaries.filter(|it| current_set.contains(*it)));
   |                                                           ---- ^^^^^^^^^^^ borrowed value does not live long enough
   |                                                           |
   |                                                           value captured here
23 |     }
   |     - `current_set` dropped here while still borrowed
...
30 | }
   | - borrow might be used here, when `common_binaries` is dropped and runs the destructor for type `std::boxed::Box<dyn std::iter::Iterator<Item = &str>>`
   |
   = note: values in a scope are dropped in the opposite order they are defined

.
Note that the borrow is also used in the println statement, so that it is not enough to define current_set before common_binaries.

But what's the problem? I mean, the closure only returns bool which is Copy!

Playground

(only out of interest, I do not need this code)

The current_set variable is dropped at the end of the iteration, but you're trying to use it inside the closure which exists after the for loop ends. Use a move closure to move the current_set into the closure:

for current_set in binaries {
    common_binaries = Box::new(common_binaries.filter(move |it| current_set.contains(*it)));
}

playground

2 Likes

Note that when you initialize the first iterator, you use an unwrap which fails if the list is empty:

let mut common_binaries: Box<dyn Iterator<Item = &str>> =
    Box::new(binaries.pop().unwrap().into_iter());

However using Option::into_iter followed by flatten you can initialize it in a way that results in an empty iterator if binaries is empty:

let mut common_binaries: Box<dyn Iterator<Item = &str>> =
    Box::new(binaries.pop().into_iter().flatten());

playground

Thanks!

It looks like you don't know how closures are desugared! You can learn how closures are represented as normal structs in my blog post dissecting closures,

2 Likes