Understanding Rust Error E0373
Introduction
Rust Error E0373 occurs when a captured variable in a closure may not live long enough, resulting in potential unsafe behavior. This article provides a detailed explanation of the error and demonstrates examples to help you understand and resolve it.
Erroneous Examples
Example: Returning a Closure
In this example, the error is triggered by a closure being returned from a function.
#![allow(unused)]
fn main() {
fn foo() -> Box<Fn(u32) -> u32> {
let x = 0u32;
Box::new(|y| x + y)
}
}
Here, x is stack-allocated by the foo() function. By default, Rust captures closed-over data by reference, meaning that x will no longer exist after foo() returns, resulting in unsafe access attempts.
Example: Spawning Threads
In this example, we'll see the error occurring due to spawning threads.
#![allow(unused)]
fn main() {
fn foo() {
let x = 0u32;
let y = 1u32;
let thr = std::thread::spawn(|| {
x + y
});
}
The stack frame containing x and y may have disappeared by the time we try to use them in the new thread, leading to unsafe behavior. Even with a thr.join() call within foo(), the compiler cannot guarantee safety and issues the error.
Example: Using Async Blocks
Error E0373 can also occur with async blocks. Here's an example:
#![allow(unused)]
fn main() {
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!()
}}
Just like closures, async blocks are not executed immediately and may capture closed-over data by reference, which can potentially outlive the data it captures.
Solutions
The solution is generally to use a move closure that moves or copies the data into the closure, eliminating the need to worry about the original data's lifetime. Here's an example:
#![allow(unused)]
fn main() {
fn foo() -> Box<Fn(u32) -> u32> {
let x = 0u32;
Box::new(move |y| x + y)
}
}
By using the move keyword, the closure now has its copy of x, ensuring safety.
Conclusion
Rust Error E0373 stems from the potential unsafe use of captured variables in a closure. To resolve this error, use a move closure that safely moves or copies the necessary data into the closure. This ensures that the data's lifetime is no longer a concern, allowing your code to compile and run safely.