Functions and Closures
A function in Rust is a recipe card. You read it, you do what it says, you put it back on the shelf the same way you found it. A closure is the metal tally clicker a nightclub doorman wears on his belt — same shape, same job, but with a tiny window on top that remembers a number between presses. The recipe card forgets you the moment you walk away. The clicker remembers every press from the door at 9pm to the door at 2am. The whole point of this lesson is that Rust gives you both, draws a hard line between them, and then sorts the clickers into three sharp categories based on how the doorman is allowed to touch the dial.

The recipe side is simple and old. The keyword fn carves out a function — a name, an input list, an arrow, an output type, a block of code. No surprises.
fn add_one(n: i32) -> i32 {
n + 1
}Pass add_one the number 4 and you get 5. Pass it 5 and you get 6. Call it ten thousand times and the function has not learned a thing about the previous calls. It cannot. There is no pocket inside fn to keep a number in. Every call starts fresh because functions are pure recipes — input goes in the top, output comes out the bottom, and the kitchen forgets you walked through.
The interesting half of the lesson starts when you want the kitchen to remember. A scoreboard that ticks up. A discount that grows each time the cashier pulls it. An iterator that knows where it left off. You cannot do this with fn alone. The function would need somewhere to stash the count between calls, and a plain function has no such place. The word for the thing that does is closure — coined by a British computer scientist named Peter Landin in 1964. Landin was reading Alonzo Church's lambda calculus and trying to build a machine that could evaluate any expression. He realized a small block of code that referred to a variable from the outside world needed to carry that variable along with it, the way an astronaut carries their air. He called the bundle of code-plus-captured-variables a closure because the code was "closed over" the variables it needed. The name stuck for the next sixty years.
fn make_counter() -> impl FnMut() -> u32 {
let mut count = 0;
move || {
count += 1;
count
}
}make_counter builds a tally clicker and hands it to you. Inside the function, count starts at zero. The closure is the move || { count += 1; count } block — two pipes for the empty argument list, then a body that bumps the count and returns the new value. The move keyword tells Rust to physically pack count into the clicker before you walk away with it, so the variable lives inside the closure for the rest of its life. The clicker is now a little metal box with a hidden compartment, and the only thing in the compartment is the number count. Every time you press it, the number goes up by one and the new value comes out the top.
Press it three times and watch.
fn run_peek<F: Fn() -> u32>(f: F) -> u32 {
f()
}
fn run_twice<F: FnMut() -> u32>(mut f: F) -> u32 {
f();
f()
}
fn run_once<F: FnOnce() -> String>(f: F) -> String {
f()
}There is a hierarchy hiding behind those three function signatures, and once you see it you will see it in every Rust codebase you read for the rest of your life. The Rust team — Niko Matsakis leading the design — locked it in around 2014 when they were trying to figure out how a closure could mean three different things at once. A doorman with a clicker might just want to read the number without touching the dial. He might want to press the button. Or he might want to rip the dial off entirely and hand it to his replacement. Three different relationships to the captured value, three different traits — Fn, FnMut, FnOnce. The compiler picks the strongest one your closure needs and writes it into the type for you.
Fn is the read-only doorman. The closure can peek at what it captured, run as many times as you want, in parallel from multiple threads if you like, but it can never change what it sees. FnMut is the doorman who is allowed to press the button — the closure can mutate the captured value, so each call can leave a mark, but only one caller can hold the clicker at a time. FnOnce is the doorman who tears the dial off. The closure consumes whatever it captured, which means you can only call it one time before the captured thing is gone and the closure with it. Every closure is FnOnce by default. Some are also FnMut. A smaller few are also Fn. The hierarchy nests — every Fn is also an FnMut is also an FnOnce, the same way every square is also a rectangle.

Run the whole binary and you see all three behaviors line up.
add_one(4) = 5
add_one(add_one(4)) = 6
clicker click = 1
clicker click = 2
clicker click = 3
Fn peek(tip=3) = 3
Fn peek(tip=3) = 3
FnMut bump x2 = 2
tally after bumps = 2
FnOnce tear = loyaltyLook at the clicker output. The first call returns 1, the second returns 2, the third returns 3. The number is not in your program's main scratchpad anywhere — it lives inside the closure's own private stack frame, a tiny struct the compiler built for you the moment you wrote move ||. If you wrote the same closure twice you would get two clickers, each with its own count, neither one able to see the other. This is how Rust gives you state without globals and without classes. The closure is the smallest object the language can make.

One question worth answering — why does the FnOnce example use move while the Fn and FnMut examples in main do not? The card value is a String, which owns memory on the heap, and the closure swallows it whole on the way out. Rust forces move here because handing the String away means it cannot live in two places at once. The other two captures are small numbers Rust copies for free, or references the closure can borrow. The compiler picked the cheapest path for each one and the strictest trait the body forced on it.
Next lesson — how the standard library chains closures together into lazy pipelines that walk a collection one item at a time without ever building the intermediate list in memory.