RAII - Rust By Example
Description: Rust by Example (RBE) is a collection of runnable examples that illustrate various Rust concepts and standard libraries.

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# RAII

Rust 中的变量不仅仅是在栈上保存数据：它们还拥有资源，例如 `Box<T>` 拥有堆上的内存。Rust 强制执行 RAII（资源获取即初始化），因此每当一个对象离开作用域时，它的析构函数就会被调用，它拥有的资源也会被释放。

这种行为可以防止资源泄漏错误，因此你再也不用手动释放内存或担心内存泄漏了！以下是一个简单示例：

    // raii.rs
    fn create_box() {
        // 在堆上分配一个整数
        let _box1 = Box::new(3i32);

        // `_box1` 在此处被销毁，内存被释放
    }

    fn main() {
        // 在堆上分配一个整数
        let _box2 = Box::new(5i32);

        // 一个嵌套的作用域：
        {
            // 在堆上分配一个整数
            let _box3 = Box::new(4i32);

            // `_box3` 在此处被销毁，内存被释放
        }

        // 创建大量的 box（仅为演示）
        // 无需手动释放内存！
        for _ in 0u32..1_000 {
            create_box();
        }

        // `_box2` 在此处被销毁，内存被释放
    }

当然，我们可以使用 `valgrind` 来再次检查内存错误：

    $ rustc raii.rs && valgrind ./raii
    ==26873== Memcheck, a memory error detector
    ==26873== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==26873== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
    ==26873== Command: ./raii
    ==26873==
    ==26873==
    ==26873== HEAP SUMMARY:
    ==26873==     in use at exit: 0 bytes in 0 blocks
    ==26873==   total heap usage: 1,013 allocs, 1,013 frees, 8,696 bytes allocated
    ==26873==
    ==26873== All heap blocks were freed -- no leaks are possible
    ==26873==
    ==26873== For counts of detected and suppressed errors, rerun with: -v
    ==26873== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

这里没有内存泄漏！

## 析构函数

Rust 中的析构函数概念是通过 `Drop` trait 提供的。当资源离开作用域时，析构函数会被调用。并非每种类型都需要实现这个 trait，只有当你需要为自己的类型实现特定的析构逻辑时才需要实现它。

运行下面的示例来了解 `Drop` trait 是如何工作的。当 `main` 函数中的变量离开作用域时，自定义的析构函数将被调用。

    struct ToDrop;

    impl Drop for ToDrop {
        fn drop(&mut self) {
            println!("ToDrop 正在被丢弃");
        }
    }

    fn main() {
        let x = ToDrop;
        println!("创建了一个 ToDrop！");
    }

### 另请参阅：

Box