🎓 A1Learner
🔍

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 moment

A 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?