In this lesson, you will learn how the Rust compiler tracks the validity of function pointers when they are passed as arguments to other functions.
The Nature of Function Pointers
In Rust, a function pointer (fn(T) -> U) is not a closure; it does not capture any environment. Because they carry no hidden data, they are essentially just memory addresses pointing to executable code. Since code segments in your binary exist for the entire duration of the program, function pointers are 'static.
However, complications arise when we use these pointers inside structures or higher-order functions that might involve references.
Function Pointers as Parameters
When you pass a function pointer to another function, you don't usually need to annotate lifetimes. Because a function pointer is essentially a copy-able, static address, it satisfies any lifetime constraint you could possibly throw at it.
Consider this example:
fn execute(func: fn(&str) -> usize, input: &str) -> usize {
func(input)
}
fn get_len(s: &str) -> usize {
s.len()
}
fn main() {
let name = String::from("Rust");
let result = execute(get_len, &name);
println!("Length: {}", result);
}
In this code, execute accepts a function pointer. Even though the input reference has a specific lifetime tied to the main stack frame, the func pointer itself is valid for the 'static lifetime.
Why Does This Matter?
If you store a function pointer inside a struct that requires a lifetime, you might be tempted to add a lifetime parameter, like struct Processor<'a> { callback: fn(&'a str) -> () }. While this is syntactically valid, it is often unnecessary. Because the function pointer is effectively global code, it doesn't "hold onto" the data it operates on. It only processes the data passed to it at the moment of execution.
If your function pointer needs to work with specific references that have a shorter lifetime than 'static, the lifetime constraints will be applied to the arguments of the function pointer, not the function pointer itself. The compiler ensures that the reference passed into the function matches the expected lifetime of the function's signature.
Key Takeaway: Function pointers are inherently 'static because they represent static code, so you only need to concern yourself with the lifetimes of the references the function pointer processes, not the pointer itself.