Use of `iter_mut` + closure that uses a reference

Hello,

I have a small snippet of code that doesn't compile and I would like to understand a bit more why.

use std::path::PathBuf;

pub fn test() {
    let v = [PathBuf::new(), PathBuf::new()];
    let _max = v.iter().max_by_key(|s| s.file_name());
}

This piece of code compile, there are no issues, and _max contains a reference to a specific value inside v.

Now if I want a mutable reference, I naively wrote

use std::path::PathBuf;

pub fn test() {
    let mut v = [PathBuf::new(), PathBuf::new()];
    let _max = v.iter_mut().max_by_key(|s| s.file_name());
}

However, this time

error: lifetime may not live long enough
 --> src/lib.rs:5:44
  |
5 |     let _max = v.iter_mut().max_by_key(|s| s.file_name());
  |                                         -- ^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
  |                                         ||
  |                                         |return type of closure is Option<&'2 OsStr>
  |                                         has type `&'1 &mut PathBuf`

And I don't think I have a real understanding of what's happening.
Is it because there is both a mutable ref and immutable ref at the same time ?
Any way I could get around this issue (maybe by not using a closure but a function with lifetime, I tried but without success) ?

Thank you very much for your time

The closure has to take an outer reference of any lifetime, but return the same type for every input -- including any lifetimes. When the inner reference is shared (&_), you can just copy that out and keep the lifetimes the same. But when they're exclusive (&mut _), you have to reborrow through the outer reference, and you can only reborrow for the lifetime of the outer reference.

So you try to return something with the outer reference lifetime, which differs every call.

It's like how here:

fn foo<I, O, F: Fn(&I) -> O>(f: F) {}

The input lifetime can't be part of O, because type parameters represent a single type (and types that differ by lifetime are distinct types).

See also


You could basically implement your own max_by_key without the single output restriction, or you could break up the finding and &mut borrowing steps.

1 Like

Thanks for the explanations as well as the provided resources, these are helpful !

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.