RustArena

Step 7 of 7

Drop and Deref

Drop: code that runs when a value goes away

In the ownership module you saw that a value is dropped at the end of its scope: its memory is freed. Drop lets you run your own code at that moment.

struct Connection {
    id: u32,
}

impl Drop for Connection {
    fn drop(&mut self) {
        println!("closing connection {}", self.id);
    }
}

fn main() {
    let _a = Connection { id: 1 };
    {
        let _b = Connection { id: 2 };
        println!("inner scope ends");
    }
    let c = Connection { id: 3 };
    drop(c);
    println!("main ends");
}
inner scope ends
closing connection 2
closing connection 3
main ends
closing connection 1

This pattern is called RAII ("resource acquisition is initialization"): a value owns a resource and releases it in Drop, so you can't forget. Files close themselves, MutexGuards unlock their mutex, network connections hang up. You rarely write Drop for plain data; you write it for types that own something outside your program's memory.

Deref (briefly): * and automatic method calls

Deref lets a wrapper type act like a reference to what it contains. You use it all the time without noticing: a String derefs to str (that's why &String works where &str is expected) and a Vec<T> derefs to [T].

use std::ops::Deref;

struct Username(String);

impl Deref for Username {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

fn greet(name: &str) -> String {
    format!("hi {name}")
}

fn main() {
    let u = Username(String::from("ferris"));
    println!("{} {}", u.len(), u.to_uppercase());
    println!("{}", greet(&u));
}
6 FERRIS
hi ferris

Use Deref for smart pointers and thin wrappers like this one. The smart pointers module comes back to Deref and Drop in depth.

Common mistakes

Your task

Implement Drop for Connection so it prints close <id> when it's dropped. Don't change main. The program must print exactly:

open 1
open 2
using 2
close 2
open 3
close 1
end of main
close 3

Challenge 2

Fill in the blanks so Noisy prints drop <name> when it's dropped. Three values are created in one scope; notice the order they're dropped in. The program prints:

made all three
drop c
drop b
drop a

Challenge 3

A Tag wraps a String that's always lowercase. Write fn new(text: &str) -> Tag that lowercases the text, and implement Deref with Target = str, so a Tag can use every str method (len, starts_with...) and be passed where a &str is expected.

Previous: Default and AsRef