Rust RAII
RAII drops a value when its owner ends. It is why Rust code needs no manual free calls and no finally blocks.
A value holds its resource
A Box owns heap memory. There is no free call to remember — the memory goes when the owner does:
let _b = Box::new(String::from("hi"));
// when _b's scope ends, the String is freed at exactly that momentA guard is just a struct with Drop
Any type can announce the end of a scope. Give it a Drop impl. It then acts the moment its owner leaves the block.
struct Bell;
impl Drop for Bell {
fn drop(&mut self) {
println!("bell rings: scope over");
}
}The guard acts when the scope ends
The bell is created inside the block. So its Drop runs exactly at the closing brace. It does not wait for the end of the program.
{
let _bell = Bell;
println!("working");
}
println!("after");A name holds it, an underscore drops it
let _ = value drops the value on that very line. Give the value a name instead, and it lives until the scope ends:
let _ = Bell;
println!("between");
let _bell = Bell;End it early with drop
std::mem::drop runs the cleanup now, before the scope ends:
let _bell = Bell;
drop(_bell);
println!("after the drop");Example
struct Cleanup {
name: &'static str,
}
impl Drop for Cleanup {
fn drop(&mut self) {
println!("cleaning up {}", self.name);
}
}
fn main() {
let _outer = Cleanup { name: "outer" };
{
let _inner = Cleanup { name: "inner" };
println!("inside the block");
}
println!("back outside");
for _ in 0..2 {
let _temp = Cleanup { name: "temp" };
}
println!("loop done");
}Key points
- RAII stands for Resource Acquisition Is Initialization.
- It is a long name for a simple rule.
- A value is born holding its resource.
- It gives the resource up when it dies.
- Cleanup runs on every way out.
- The normal end of a block drops the local values.
- An early return drops them too.
- Even panic unwinding drops them on the way.
- A guard can mediate every touch of the resource.
- MutexGuard implements Deref.
- So the locked value is reachable only while the guard lives.
- Drop the guard and the access ends with it.
- In Rust the moment is exact: the closing brace of the owner.
- Heap memory, open files, locks, and network links all follow this one rule.
In this example, Cleanup prints a line when it is dropped, so you can watch RAII happen. The inner value is created inside its own block. First, inside the block prints. Then the block ends. At exactly that moment, cleaning up inner prints. The loop makes a fresh temp value each round. Each one is dropped at the end of its round. So cleaning up temp prints twice, before loop done. The outer value lives longest: its cleanup prints last of all, when main ends.
Note
Garbage-collected languages free memory when a collector happens to run, so a file or a lock can linger for a while.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
When does a local Box free its heap memory?