Callables and Closures
Named functions, builtins, and closures are first-class callable values. They can be annotated, passed, returned, selected by control flow, and stored in arrays or maps.
Callable schemas
A callable schema uses fn(ParamTypes...) -> ResultType.
fn add_one(value: int) -> int {
value + 1
}
let operation: fn(int) -> int = add_one;
operation(41);
Named function values
Referencing a function without () creates a callable value.
fn double(value: int) -> int {
value * 2
}
let operation = double;
operation(21);
Builtin function values
Builtins can also be captured and called as values.
let measure: fn(string) -> int = len;
measure("RustScript");
Higher-order functions
Callable values can be passed as parameters.
fn apply_twice(mapper: fn(int) -> int, value: int) -> int {
mapper(mapper(value))
}
fn add_one(value: int) -> int {
value + 1
}
apply_twice(add_one, 40);
Returned callables
Functions can return named functions or closures.
fn add_one(value: int) -> int {
value + 1
}
fn select() -> fn(int) -> int {
add_one
}
let operation = select();
operation(41);
Callable arrays and maps
Collections can store callables and return them through indexing or field access.
fn add_one(value: int) -> int { value + 1 }
fn add_two(value: int) -> int { value + 2 }
let operations = [add_one, add_two];
let named = {primary: add_one};
let from_array = operations[1];
let from_map = named.primary;
from_array(40) + from_map(0);
Closures
A closure uses pipe-delimited parameters followed by an expression or expression block.
let base = 40;
let add = |value| value + base;
add(2);
Zero-parameter closures
|| expression declares a closure without parameters.
let value = 42;
let read = || value;
read();
Escaping closures
A returned closure retains its captured environment after the defining function returns.
fn make_adder(delta: int) -> fn(int) -> int {
|value| value + delta
}
let add_one = make_adder(1);
add_one(41);
Shared mutable capture state
Aliases of one closure share its environment; separate factory evaluations allocate independent environments.
fn make_counter() {
let mut count = 0;
fn next() {
count = count + 1;
count
}
next
}
let first = make_counter();
let alias = first;
let second = make_counter();
[first(), alias(), second()];
Borrowed captures
A borrow capture observes the shared outer cell instead of taking an owned snapshot.
let mut base = 1;
let read = || &base;
base = 2;
[read(), base];
Generic function values
A callable annotation or explicit turbofish resolves a generic function value.
fn identity<T>(value: T) -> T {
value
}
let int_identity: fn(int) -> int = identity;
let string_identity = identity::<string>;
int_identity(42);
string_identity("rss");
Callable selection and equality
Compatible callable schemas merge through if and match. Equality follows function-item and closure-environment identity.
fn add_one(value: int) -> int { value + 1 }
fn add_two(value: int) -> int { value + 2 }
let selected = if true => { add_one } else => { add_two };
let first = |value| value + 1;
let second = |value| value + 1;
[selected(40), add_one == add_one, first == first, first == second];