Function Pointers (fn) / Higher-Order Functions
In Rust, you can use function pointers (fn type) to treat functions as values. Unlike closures, function pointers do not capture variables from the surrounding environment. They are useful for higher-order function patterns where you pass a function as an argument.
Syntax
// Function pointer type: fn(parameter type) -> return type
fn add(x: i32, y: i32) -> i32 { x + y }
let f: fn(i32, i32) -> i32 = add;
// Higher-order function that accepts a function as an argument
fn apply(f: fn(i32) -> i32, x: i32) -> i32 { f(x) }
// A vector of function pointers
let funcs: Vec<fn(i32) -> i32> = vec![double, square];
// Passing a method as a function pointer (UFCS notation)
let doubled: Vec<i32> = nums.iter().map(|x| x * 2).collect();
let lengths: Vec<usize> = words.iter().map(|s| s.len()).collect();
Concept Reference
| Notation | Description |
|---|---|
| fn(T) -> U | Function pointer type. No captures. More lightweight than a closure. |
| Fn(T) -> U | Closure trait. Function pointers also implement this trait. |
| map(str::len) | Passes an existing function directly to map and similar methods (UFCS notation). |
| Type::method | An associated function or method on a type can be used as a function pointer. |
| Higher-order function | A function that takes another function as an argument or returns one as its result. |
Sample Code
// Function definitions used as function pointers
fn double(x: i32) -> i32 { x * 2 }
fn square(x: i32) -> i32 { x * x }
fn is_even(x: &i32) -> bool { x % 2 == 0 }
// Higher-order function that accepts a slice of function pointers
fn apply_all(funcs: &[fn(i32) -> i32], x: i32) -> Vec<i32> {
funcs.iter().map(|f| f(x)).collect()
}
fn main() {
// Assign a function pointer to a variable.
let f: fn(i32) -> i32 = double;
println!("double(5) = {}", f(5)); // 10
// An array of function pointers
let ops: Vec<fn(i32) -> i32> = vec![double, square];
let results = apply_all(&ops, 4);
println!("results: {:?}", results); // [8, 16]
// Pass an existing function directly to map.
let words = vec!["hello", "world", "rust"];
let lengths: Vec<usize> = words.iter().map(str::len).collect();
println!("lengths: {:?}", lengths); // [5, 5, 4]
// Pass a function pointer to filter.
let nums = vec![1, 2, 3, 4, 5, 6];
let evens: Vec<&i32> = nums.iter().filter(is_even).collect();
println!("evens: {:?}", evens); // [2, 4, 6]
// Use String::from with map.
let strs = vec!["a", "b", "c"];
let owned: Vec<String> = strs.iter().map(|s| s.to_string()).collect();
println!("owned: {:?}", owned);
// Higher-order function that returns a function (returns a closure)
fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
move |x| x + n
}
let add5 = make_adder(5);
let add10 = make_adder(10);
println!("add5(3) = {}", add5(3)); // 8
println!("add10(3) = {}", add10(3)); // 13
// Callback pattern
fn transform(data: &[i32], callback: fn(i32) -> i32) -> Vec<i32> {
data.iter().map(|&x| callback(x)).collect()
}
let doubled = transform(&[1, 2, 3, 4], double);
println!("doubled: {:?}", doubled); // [2, 4, 6, 8]
}
Overview
The function pointer type fn(T) -> U is a reference to a plain function with no captured state. Unlike the closure traits Fn, FnMut, and FnOnce, function pointers do not reference data on the stack, so they can be safely shared across threads.
You can pass existing functions directly to iterator adapters like map(str::len) or filter(is_even). This can be more concise than writing a closure such as |s| s.len().
When returning a function, using impl Fn() as the return type is convenient — the Rust compiler infers the exact type. If the closure needs to capture variables, add the move keyword. For details on closure traits, see Fn / FnMut / FnOnce Traits.
If you find any errors or copyright issues, please contact us.