Hi, I have a question about sharing higher-rank trait bound lifetimes between two bounds.
I wrote this function:
async fn calc<T, TFut, F>(action: F) -> T
where
TFut: Future<Output = T>,
F: FnOnce(&mut i32) -> TFut,
{
let mut num = 42;
action(&mut num).await
}
It compiles just fine, but when it is called and num
is used in the closure, it fails:
async fn run() {
let result = calc(|num| async move {
*num
}).await;
println!("{:?}", result);
}
error message
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:11:40
|
11 | let result = calc(|num| async move {
| ________________________________________^
12 | | *num
13 | | }).await;
| |_____^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 11:23...
--> src/main.rs:11:23
|
11 | let result = calc(|num| async move {
| _______________________^
12 | | *num
13 | | }).await;
| |_____^
note: ...so that the types are compatible
--> src/main.rs:11:40
|
11 | let result = calc(|num| async move {
| ________________________________________^
12 | | *num
13 | | }).await;
| |_____^
= note: expected `&mut i32`
found `&mut i32`
note: but, the lifetime must be valid for the call at 11:18...
--> src/main.rs:11:18
|
11 | let result = calc(|num| async move {
| __________________^
12 | | *num
13 | | }).await;
| |______^
note: ...so type `impl core::future::future::Future` of expression is valid during the expression
--> src/main.rs:11:18
|
11 | let result = calc(|num| async move {
| __________________^
12 | | *num
13 | | }).await;
| |______^
I understand that this happens, because the Future
returned by the closure may outlive the num
.
In order to fix this, I'd like to specify something like this to communicate in the function
signature that num
always outlives the Future
:
async fn calc<T, TFut, F>(action: F) -> T
where
TFut: Future<Output = T> + 'lifetime,
F: FnOnce(&'lifetime mut i32) -> TFut,
{
let mut num = 42;
action(&mut num).await
}
However I don't know where to define 'lifetime
. If I define it on either one of the bounds, it
cannot be referenced on the other one:
async fn calc<T, TFut, F>(action: F) -> T
where
for <'lifetime> TFut: Future<Output = T> + 'lifetime,
F: FnOnce(&'lifetime mut i32) -> TFut,
{
let mut num = 42;
action(&mut num).await
}
error message
error[E0261]: use of undeclared lifetime name `'lifetime`
--> src/main.rs:21:16
|
21 | F: FnOnce(&'lifetime mut i32) -> TFut,
| ^^^^^^^^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider introducing lifetime `'lifetime` here
|
18 | async fn calc<'lifetime, T, TFut, F>(action: F) -> T
| ^^^^^^^^^^
help: consider making the bound lifetime-generic with a new `'lifetime` lifetime
|
21 | F: for<'lifetime> FnOnce(&'lifetime mut i32) -> TFut,
| ^^^^^^^^^^^^^^
So my question is this:
Is there a way to specify 'lifetime
like above and make this function work?