1

I have an iterator that maps over some values, creating tuples on the way. I need to get the maximum by one of the elements on the tuple (which is not Copy), but interior references are getting in the way (as was expected when it got stabilised).

How can I make something like this work?

// Not a Copy type!
#[derive(Ord, PartialOrd, Eq, PartialEq)]
struct t(i8);

fn main() {
    // This works
    let v = vec![(t(0),), (t(1),)];
    v.iter().min_by_key(|v| &v.0);

    // This doesn't
    let v = vec![0, 1];
    v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
}

Playground

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:12:47
   |
12 |     v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
   |                                               ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 12:43...
  --> src/main.rs:12:43
   |
12 |     v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
   |                                           ^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:12:47
   |
12 |     v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
   |                                               ^^^^
note: but, the lifetime must be valid for the method call at 12:5...
  --> src/main.rs:12:5
   |
12 |     v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that a type/lifetime parameter is in scope here
  --> src/main.rs:12:5
   |
12 |     v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Rubén Durá Tarí
  • 1,050
  • 1
  • 10
  • 18

1 Answers1

4

They cannot. As values flow through iterator adapters, they are moved. Moving a value causes any references to it to be invalidated. You are attempting to take a reference to a value that only exists in the iterator pipeline; the reference cannot live long enough. This is equivalent to this basic example:

(0..9).map(|x| &x)

You will need to use Iterator::min_by:

v.iter().map(|i| (X(*i),)).min_by(|a, b| a.0.cmp(&b.0));

This works because the returned value from the closure is an Ordering with no references to the original values.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366