Stuck: chain of iterators

I have written the following code:

use fancy_regex::{Regex, Captures};

/// Returns an iterator with all captures of named groups
/// whose names match `predicate`
fn pairs<'a>(regex: &'a Regex, captures: &'a Captures, predicate: &'a fn (&str) -> bool) -> impl Iterator<Item=(String, String)> + 'a {
    regex.capture_names()
    .zip(&mut captures.iter())
    .filter_map(|(name_opt, match_opt)| {
        if let (Some(name), Some(match_)) = (name_opt, match_opt) {
            if predicate(&name) {
                let pair = (
                    name.to_string(),
                    match_.as_str().to_string()
                );
                return Some(pair);
            }
        }
        None
    })
}

Error message:

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:6:5
   |
6  | /     regex.capture_names()
7  | |     .zip(&mut captures.iter())
   | |               --------------- temporary value created here
8  | |     .filter_map(|(name_opt, match_opt)| {
9  | |         if let (Some(name), Some(match_)) = (name_opt, match_opt) {
...  |
18 | |         None
19 | |     })
   | |______^ returns a value referencing data owned by the current function
   |
   = help: use `.collect()` to allocate the iterator

This is my second day with Rust, so I’m still mostly winging it:

  • I’m unsure about the lifetime annotation 'a but it made several compiler errors go away.
  • The Iterator method .filter() has a relatively complex type (MutFn etc.) for its callback which makes me wonder if the type of predicate is OK.
  • IINM, .collect() returns a collection so I’m not sure how it would help.
  • I tried .clone() at the end but that didn’t work either.

Any help welcome, thanks!

  • fn() is already a pointer, don't borrow function pointers.
  • iter() already gives an iterator that can be mutated (temporary values are mutable by default). Don't add another layer of temporaryness and indirection to it.

By using &mut captures.iter() you're not zipping with captures.iter(), but zipping with a temporary loan of an implicit temporary local variable that holds the captures.iter() result for this expression. This causes you trouble, because you can't return anything that depends on (an implicit) local variable.

(I'm assuming fancy_regex is close enough to the regex crate here.)

captures.iter() returns a value which you immediately take a &mut to, without binding it anywhere. That's the temporary it's talking about. The &mut can't be longer than the function body, and thus the error.

You don't need to take a &mut here -- what captures.iter() returns is already an iterator you can feed to zip. So the minimal fix is to remove that &mut.


There's no reason to have a reference to a fn(...) (much less with a named lifetime) as fn(...) are function pointer types -- they're already a type of pointer. It's also more idiomatic to take a generic in this case, to allow more flexibility to the caller.

You could return &strs here and let the caller decide if they want to make the conversion to Strings or not.

Playground.

Thanks, that helps!

  • I added the &mut earlier to make the compiler happy but it’s indeed what’s causing the problem.
  • If I remove &'a or 'a before the function pointer then I get an error.

Thanks for the tips and the code! TIL: Fn vs. FnMut vs. FnOnce

You can just follow the compiler advice in that case (removing &'a) and make the closure a move closure.

1 Like

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.