Reputation: 3224
I encounter some problems, when implementing an argmax
function. Here is an MVCE (link to v1 playground):
fn main() {
let c = [4,5,6,1];
let min = argmin(&c);
println!("{}", min);
}
fn argmin(arr: &[i32]) -> usize {
arr.iter()
.enumerate()
.min_by_key(|(_, v)| v)
.map(|(idx, _)| idx)
.unwrap()
}
Which results in some lifetime errors:
error: lifetime may not live long enough
--> src/main.rs:10:50
|
10 | .min_by_key(|(_, v): &(usize, &i32)| v)
| - - ^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 &i32
| let's call the lifetime of this reference `'1`
error: aborting due to previous error
Granted. There is no guarantee that the a reference to the minimum value of the vector outlives the (reference to the) vector from which it's coming. This led me to the following adaptations (link to v2 playground):
fn main() {
let c = [4,5,6,1];
let min = argmin(&c);
println!("{}", min);
}
fn argmin<'a>(arr: &'a [i32]) -> usize {
arr.iter()
.enumerate()
.min_by_key(|(_, v): &'a (usize, &i32)| v)
.map(|(idx, _)| idx)
.unwrap()
}
I would think now, that Rust can figure out that both c
and its minimum have the same lifetime with the information from the argmin
's signature. But what I receive is another compiler error:
error[E0308]: mismatched types
--> src/main.rs:10:34
|
10 | .min_by_key(|(_, v): &'a (usize, &i32)| v)
| ^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected reference `&(usize, &i32)`
found reference `&'a (usize, &i32)`
note: the anonymous lifetime #1 defined on the body at 10:25...
--> src/main.rs:10:25
|
10 | .min_by_key(|(_, v): &'a (usize, &i32)| v)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the function body at 7:11
--> src/main.rs:7:11
|
7 | fn argmin<'a>(arr: &'a [i32]) -> usize {
| ^^
error[E0308]: mismatched types
--> src/main.rs:10:34
|
10 | .min_by_key(|(_, v): &'a (usize, &i32)| v)
| ^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected reference `&(usize, &i32)`
found reference `&'a (usize, &i32)`
note: the lifetime `'a` as defined on the function body at 7:11...
--> src/main.rs:7:11
|
7 | fn argmin<'a>(arr: &'a [i32]) -> usize {
| ^^
note: ...does not necessarily outlive the anonymous lifetime #1 defined on the body at 10:25
--> src/main.rs:10:25
|
10 | .min_by_key(|(_, v): &'a (usize, &i32)| v)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What is happening here? To me it seems like the lifetime in the function signature can't be matched to the one in min_by_key
. How can we fix this in a proper way, using lifetimes? Can we even do it?
P.S.: I know that this can easily be fixed by just using a clone (.min_by_key(|(_, v)| v.clone())
) in line 10.
Upvotes: 2
Views: 614
Reputation: 42756
So, it is a bit tricky, but it is due because of a double reference. If I'm correct. Notice the double reference &(usize, &i32)
. So, in reality you are getting a &usize
and a &&i32
. For solving that, just match the outer reference in the closure:
fn argmin(arr: &[i32]) -> usize {
arr.iter()
.enumerate()
.min_by_key(|&(_, v): &(usize, &i32)| v)
.map(|(idx, _)| idx)
.unwrap()
}
Upvotes: 1