I'm using the AWS Lambda (via the lambda_http crate) and the following code doesn't compile:
let handler = service_fn(move |event: Request| async {
handler_organization_post(&shared_client, event).await
});
lambda_http::run(handler).await
error: lifetime may not live long enough
--> organization/organization_post/src/main.rs:125:52
|
125 | let handler = service_fn(move |event: Request| async {
| ______________________________---------------------_^
| | | |
| | | return type of closure `[async block@organization/organization_post/src/main.rs:125:52: 127:6]` contains a lifetime `'2`
| | lifetime `'1` represents this closure's body
126 | | handler_organization_post(&shared_client, event).await
127 | | });
| |_____^ returning this value requires that `'1` must outlive `'2`
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
However, if I simply inline the closure declaration into the call to lambda_http::run
, the program compiles and runs with no problems:
lambda_http::run(service_fn(move |event: Request| async move {
handler_organization_post(&shared_client, event).await
})).await
In my head, these are semantically equivalent, so what's going on? I'm clearly missing something and would appreciate a pointer in the right direction.
You need to use async move
for the closure to be valid. This is the difference between the two versions of your code - the second uses async move
, while the first does not.
To understand this, recall that an async
block evaluates to an impl Future
- to some value which implements the Future
trait. The code inside the block is not immediately executed. It is only executed when the future is “polled” - that is, when someone tries to evaluate the future and get the underlying value.
Consider a very simple closure using async
.
let closure = |y: i32| async { y + 1 };
This is actually not a valid closure. The async
block does not have the move
keyword, so the future it evaluates to contains a reference to y
, not y
itself. By the time the async
block is evaluated, this reference will no longer be valid, since the closure will have returned. To make everything work, you need to change the code to
let closure = |y: i32| async move { y + 1 };