Rust RAII 资源管理

Beginner

This tutorial is from open-source community. Access the source code

简介

在本实验中,我们将探索 Rust 中的 RAII(Resource Acquisition Is Initialization,资源获取即初始化)概念,它强制资源获取就是初始化。这意味着当对象超出作用域时,它们的析构函数会被调用,其拥有的资源会被释放,从而消除了手动内存管理的需求,并确保防止资源泄漏错误。我们还将了解 Rust 中的 Drop 特性,它允许为需要的类型实现自定义析构函数逻辑。

注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用 main.rs,并通过 rustc main.rs &&./main 进行编译和运行。

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` 在此处被销毁,内存被释放
    }

    // 只是为了好玩创建很多盒子
    // 无需手动释放内存!
    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 特性提供的。当资源超出作用域时,析构函数会被调用。并非每个类型都需要实现这个特性,只有当你的类型需要自己的析构函数逻辑时才实现它。

运行下面的示例来看看 Drop 特性是如何工作的。当 main 函数中的变量超出作用域时,自定义析构函数将会被调用。

struct ToDrop;

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

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

总结

恭喜你!你已经完成了 RAII 实验。你可以在 LabEx 中练习更多实验来提升你的技能。