| A captured variable in a closure may not live long enough. | |
| Erroneous code example: | |
| ```compile_fail,E0373 | |
| fn foo() -> Box<dyn Fn(u32) -> u32> { | |
| let x = 0u32; | |
| Box::new(|y| x + y) | |
| } | |
| ``` | |
| This error occurs when an attempt is made to use data captured by a closure, | |
| when that data may no longer exist. It's most commonly seen when attempting to | |
| return a closure as shown in the previous code example. | |
| Notice that `x` is stack-allocated by `foo()`. By default, Rust captures | |
| closed-over data by reference. This means that once `foo()` returns, `x` no | |
| longer exists. An attempt to access `x` within the closure would thus be | |
| unsafe. | |
| Another situation where this might be encountered is when spawning threads: | |
| ```compile_fail,E0373 | |
| fn foo() { | |
| let x = 0u32; | |
| let y = 1u32; | |
| let thr = std::thread::spawn(|| { | |
| x + y | |
| }); | |
| } | |
| ``` | |
| Since our new thread runs in parallel, the stack frame containing `x` and `y` | |
| may well have disappeared by the time we try to use them. Even if we call | |
| `thr.join()` within foo (which blocks until `thr` has completed, ensuring the | |
| stack frame won't disappear), we will not succeed: the compiler cannot prove | |
| that this behavior is safe, and so won't let us do it. | |
| The solution to this problem is usually to switch to using a `move` closure. | |
| This approach moves (or copies, where possible) data into the closure, rather | |
| than taking references to it. For example: | |
| ``` | |
| fn foo() -> Box<dyn Fn(u32) -> u32> { | |
| let x = 0u32; | |
| Box::new(move |y| x + y) | |
| } | |
| ``` | |
| Now that the closure has its own copy of the data, there's no need to worry | |
| about safety. | |
| This error may also be encountered while using `async` blocks: | |
| ```compile_fail,E0373,edition2018 | |
| use std::future::Future; | |
| async fn f() { | |
| let v = vec![1, 2, 3i32]; | |
| spawn(async { //~ ERROR E0373 | |
| println!("{:?}", v) | |
| }); | |
| } | |
| fn spawn<F: Future + Send + 'static>(future: F) { | |
| unimplemented!() | |
| } | |
| ``` | |
| Similarly to closures, `async` blocks are not executed immediately and may | |
| capture closed-over data by reference. For more information, see | |
| <https://rust-lang.github.io/async-book/03_async_await/01_chapter.html>. |