Course contentsShow
← Rust
Lesson 361 of 1,9104. Lifetimes and Advanced OwnershipFree lesson

Function Pointer Lifetimes

Specify the valid duration of functions passed as arguments to higher-order functions.

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.