In this lesson, you will learn how to enforce lifetime requirements when a closure is captured and stored within another object, such as a struct.
The Problem: Storing Borrowed Data
When you pass a closure to a function, the compiler usually infers the lifetimes automatically. However, when you store that closure in a struct, the compiler needs to know exactly how long the references captured by that closure will remain valid. If a closure captures a reference to a variable, the closure itself effectively "borrows" that variable.
If you want to store this closure in a struct, your struct must explicitly account for that lifetime.
Defining Constraints in Structs
Imagine you have a struct designed to hold a task (a closure). If that task needs to print a message that includes a reference to a local variable, the struct definition must mirror that lifetime:
struct Task<'a> {
// We constrain the closure to live at least as long as 'a
action: Box<dyn Fn() + 'a>,
}
fn create_task<'a>(data: &'a String) -> Task<'a> {
Task {
action: Box::new(move || println!("Data: {}", data)),
}
}
In the example above, the Task<'a> struct explicitly declares that it holds a closure that depends on a reference living for at least 'a. If we tried to store a closure that outlived the data it was referencing, the Rust compiler would throw a lifetime error.
Why Does This Matter?
Without these constraints, the compiler cannot guarantee that the captured reference is still valid when the struct invokes the closure later. By attaching the 'a lifetime to the Task struct, you are effectively telling the compiler: "This object is only valid for as long as the references inside my closure are valid."
This pattern is essential when building callback systems, event handlers, or custom schedulers where closures are stored for later execution. By binding the struct’s lifetime to the captured data, you prevent "use-after-free" bugs while maintaining the flexibility of closures.
Key Takeaway: When a struct stores a closure that captures references, you must define a lifetime parameter on the struct to bind the closure's captured data to the struct's own validity.