Rust Deref & Drop
Deref is the trait that lets a pointer be used like the value it points at. Drop is the code Rust runs automatically when a value's life ends.
Coercion: a &Vec works as a slice
Rust walks the deref chain for you. A &String is accepted where &str is expected. A &Vec<T> is accepted where &[T] is expected. It costs nothing at run time — Rust works out the whole chain while compiling.
let v = vec![1, 2, 3];
let a: &[i32] = &v;
println!("len = {}", a.len());Write through a mutable pointer
DerefMut is the companion trait for mutable pointers. It is what lets *pointer change the value behind the pointer.
let mut b = Box::new(5);
*b = 6;
println!("b = {}", b);Drop: one method does the cleanup
Drop has exactly one method, fn drop(&mut self), and Rust calls it for you. Your code runs first, while every field is still alive. Only after it returns does Rust drop the fields one by one.
impl Drop for Guard {
fn drop(&mut self) {
println!("dropping {}", self.name);
}
}Last made, first dropped
Values drop in reverse order: the last one created is the first one dropped.
{
let _a = Guard { name: "first made".into() };
let _b = Guard { name: "second made".into() };
println!("inside");
}Drop something early
std::mem::drop(value) takes ownership, so the cleanup runs right there. Never call .drop() yourself. Rust bans it with error E0040 (checked). It would run the cleanup a second time at the end of the scope. And it would free the same value twice.
let g = Guard { name: "early".into() };
drop(g);
println!("after drop");Example
struct Guard { name: String }
impl Drop for Guard { fn drop(&mut self) { println!("dropping {}", self.name); } }
fn main() {
let _a = Guard { name: "first".into() };
{ let _b = Guard { name: "inner".into() }; println!("inside block"); }
println!("after block");
}Key points
- Deref is what makes a pointer feel like the value itself: * and method calls reach straight through.
- Implementing Deref for your own pointer type makes *pointer and method calls work
- Deref coercion has three cases: &T to &U, &mut T to &mut U, &mut T to &U.
- A &T can never coerce up to a &mut U.
- Many standard types implement Drop to free what they own.
- Box frees heap memory.
- Vec and String free their buffers.
- File closes the file.
- Anti-pattern: do not implement Deref just to reuse another type's methods, like pretend inheritance.
- Deref is for types that truly act as pointers.
- For ordinary reuse, write a named method.
- Or reach the inner value with .0.
- Then readers always know which type a call lands on.
- Files, locks, and network types all use Drop to close and release themselves.
- That is why Rust code rarely needs finally blocks.
- Drop runs a value's cleanup automatically at the end of its life.
In this example, Guard is a small struct that implements Drop. Its drop code prints a message. In main, _a is created first. Inside the inner block, _b is created and "inside block" prints. When the inner block ends, _b's scope ends, so its Drop runs: "dropping inner". Back in the outer scope, "after block" prints. Finally main ends, _a goes out of scope, and "dropping first" prints. Nobody called any cleanup by hand — the scopes decided everything.
Note
This pattern has a name: RAII.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
How do you drop a value before the end of its scope?