Rust Function Pointers
A function pointer is a value that points at a plain named function. Its type is written fn, with a small f.
Name the type: fn
A function pointer type spells out what goes in and what comes out. Small f — fn is a type, not the Fn trait:
fn add_one(x: i32) -> i32 { x + 1 }
let job: fn(i32) -> i32 = add_one;
println!("job(5) = {}", job(5));Pass a function by its name
Hand the function over with no brackets after its name. Brackets would call it. The bare name passes it:
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { f(arg) + f(arg) }
println!("do_twice = {}", do_twice(add_one, 5));A generic Fn bound takes either
Ask for the Fn trait instead of plain fn, and callers may pass a function or a closure — both fit:
fn do_twice_generic<F: Fn(i32) -> i32>(f: F, arg: i32) -> i32 { f(arg) + f(arg) }
println!("fn in: {}", do_twice_generic(add_one, 5));
println!("closure in: {}", do_twice_generic(|x| x * 2, 5));Box returned closures to share one type
Every closure has its own hidden type. Box<dyn Fn> wraps them into one shared type, so a Vec can hold them side by side:
fn returns_adder() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
let handlers = vec![returns_adder(), returns_adder()];
for h in &handlers { println!("handler(5) = {}", h(5)); }An enum variant is a function too
A variant that holds data builds a value from that data. So it can be handed to map like any function:
#[derive(Debug)]
enum Status { Value(u32), Stop }
let statuses: Vec<Status> = (0u32..3).map(Status::Value).collect();
println!("statuses = {:?}", statuses);impl Fn hides a different type each time
Returning impl Fn promises the shape. But each function still returns its own hidden type. So two of them cannot share a Vec:
fn first() -> impl Fn(i32) -> i32 { |x| x + 1 }
fn second() -> impl Fn(i32) -> i32 { |x| x + 2 }
// let both = vec![first(), second()]; // error E0308: two different hidden typesExample
fn add_one(x: i32) -> i32 { x + 1 }
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { f(arg) + f(arg) }
fn returns_closure() -> Box<dyn Fn(i32) -> i32> { Box::new(|x| x + 1) }
fn returns_starting(init: i32) -> Box<dyn Fn(i32) -> i32> { Box::new(move |x| x + init) }
#[derive(Debug)]
enum Status { Value(u32), Stop }
fn main() {
println!("answer = {}", do_twice(add_one, 5));
let handlers = vec![returns_closure(), returns_starting(100)];
for handler in handlers { println!("{}", handler(5)); }
let statuses: Vec<Status> = (0u32..3).map(Status::Value).collect();
println!("statuses = {:?}", statuses);
}Key points
- A function pointer implements Fn, FnMut and FnOnce, so it fits anywhere a closure is accepted
- Ask for plain fn only when the other side has no closures — C functions are the classic case
- Return a closure with -> impl Fn(i32) -> i32 for one fixed closure shape
In this example, do_twice takes an fn pointer and calls it twice on 5: 6 + 6 prints answer = 12. The two returned closures have different hidden types. So both functions return Box<dyn Fn>. That gives them one shared type. The Vec then runs them on 5. It prints 6 and 105. Last, Status::Value is used as a function: map turns 0, 1 and 2 into [Value(0), Value(1), Value(2)].
Note
fn is a type you can name and store
Fn is a trait that closures, function pointers and a few other callables all share
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
Why return Box<dyn Fn> instead of impl Fn when collecting closures in a Vec?