error[E0521]: borrowed data escapes outside of closure
ID: rust/e0521-borrowed-data-escapes
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| 1 | active | — | — | — |
Root Cause
A closure or function captures a reference to data that may be dropped before the closure finishes. The solution is usually to transfer ownership (owned types) or use scoped threads.
genericWorkarounds
-
88% success Use owned data (String instead of &str, Vec<T> instead of &[T])
Convert borrowed references to owned types before passing to closures that escape their scope. Change &str to String::from(s), &[T] to s.to_vec(). If the closure goes to thread::spawn or tokio::spawn, all captures must be owned.
Sources: https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
-
85% success Use scoped threads to allow borrowing safely
std::thread::scope (stable since Rust 1.63) or crossbeam::scope allow spawning threads that borrow from the enclosing scope. The scope guarantees all spawned threads finish before the borrowed data goes out of scope.
-
82% success Move data creation inside the closure
Instead of creating data outside and borrowing it inside the closure, create the data inside the closure where ownership is clear from the start. This eliminates the escape entirely.
Dead Ends
Common approaches that don't work:
-
Adding .clone() on every borrowed reference indiscriminately
55% fail
Cloning works for owned types but if you have &T, cloning gives T which may not be what the API expects. It also hides performance issues with unnecessary heap allocations and can change the semantics of the code.
-
Using unsafe { std::mem::transmute() } to extend the lifetime
95% fail
This is undefined behavior. The data may be freed while the transmuted reference is still in use, causing use-after-free, data corruption, or crashes. The borrow checker exists specifically to prevent this class of bugs.