Rust 特性: Drop 特性(类 C++ 析构函数)

Rust 特性: Drop 特性(类 C++ 析构函数)

文章目录

正文

0. 关于析构函数

写过 C++ 的应该都知道,资源被释放的时候会调用析构函数,方法签名如下

class AClass {
    public:
        ~AClass();
}

Java 也有类似的函数

class Object {
    finialize();
}

但是由于 Java 引入了 GC 的概念,因此真实的资源回收时机变得模糊,可以说是一个挺失败的设计hh

当然,作为与 C 语言同层级的现代语言,Rust 也提供了相应的析构函数写法,以一个特殊的 Trait - Drop 的形式提供,实现方式如下

impl Drop for AStruct {
    fn drop(&mut self) {
        // do something before drop
    }
}

1. 代码实现

下面我们来看看代码实现,先定义两个结构体,又是熟悉的 Point 和 Rectangle

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

#[derive(Debug)]
struct Rectangle {
    top_left: Point,
    bottom_right: Point,
}

1.0 Drop 实现

然后为这两个结构体实现一个一样的 Drop 特性

use std::fmt::Debug;
use std::mem::size_of_val;

fn drop_resource<T: Debug>(item: &mut T) {
    println!("=== [release resources] {:?} ,free: {} bytes", item, size_of_val(item));
}

impl Drop for Point {
    fn drop(&mut self) {
        drop_resource(self);
    }
}

impl Drop for Rectangle {
    fn drop(&mut self) {
        drop_resource(self);
    }
}

1.1 自动回收

第一个例子我们先看自动回收的效果

  • Sample1:两个 Point
fn main() {
    let point = Point { x: -1, y: -1 };
    println!("point = {:?}", point);

    let point = Point { x: 0, y: 0 };
    println!("point = {:?}", point);
}
point = Point { x: -1, y: -1 }
point = Point { x: 0, y: 0 }
=== [release resources] Point { x: 0, y: 0 } ,free: 8 bytes
=== [release resources] Point { x: -1, y: -1 } ,free: 8 bytes

我们可以看到即便修改 point 指向,实际上 -1 的那个 Point 依旧会存活整个作用域的生命周期;同时注意到释放看起来应该是照着方法栈的顺序一一回收,不过直觉告诉我们这个顺序不可依赖

  • Sample2:Rectangle 与 Box
fn main() {
    let rect = Rectangle {
        top_left: Point { x: 1, y: 1 },
        bottom_right: Point { x: 2, y: 2 },
    };
    println!("rect = {:?}", rect);

    let box_rect = Box::new(Rectangle {
        top_left: Point { x: 3, y: 3 },
        bottom_right: Point { x: 4, y: 4 },
    });
    println!("box_rect = {:?}", box_rect);
}
rect = Rectangle { top_left: Point { x: 1, y: 1 }, bottom_right: Point { x: 2, y: 2 } }
box_rect = Rectangle { top_left: Point { x: 3, y: 3 }, bottom_right: Point { x: 4, y: 4 } }
=== [release resources] Rectangle { top_left: Point { x: 3, y: 3 }, bottom_right: Point { x: 4, y: 4 } } ,free: 16 bytes
=== [release resources] Point { x: 3, y: 3 } ,free: 8 bytes
=== [release resources] Point { x: 4, y: 4 } ,free: 8 bytes
=== [release resources] Rectangle { top_left: Point { x: 1, y: 1 }, bottom_right: Point { x: 2, y: 2 } } ,free: 16 bytes
=== [release resources] Point { x: 1, y: 1 } ,free: 8 bytes
=== [release resources] Point { x: 2, y: 2 } ,free: 8 bytes

我们发现作为 Rectangle 子元素的 Point 也会递归释放,一样顺序不可依赖(如果编译器对栈上变量做重排列会打乱顺序)

1.2 主动回收

实际上我们依赖自动回收已经很够了,同时 Rust 的资源利用跟踪机制实在是非常的好,所以我们会用到主动回收的时机是在少之又少,也是一个全局提供的 drop 函数

fn main() {
    let point = Point { x: -1, y: -1 };
    println!("point = {:?}", point);
    drop(point);

    let point = Point { x: 0, y: 0 };
    println!("point = {:?}", point);
}
point = Point { x: -1, y: -1 }
=== [release resources] Point { x: -1, y: -1 } ,free: 8 bytes
point = Point { x: 0, y: 0 }
=== [release resources] Point { x: 0, y: 0 } ,free: 8 bytes

都主动回收了,当然 drop 特性也就提前执行咯

其他资源

参考连接

Title Link
Drop - Rust by Example https://doc.rust-lang.org/rust-by-example/trait/drop.html

完整代码示例

https://github.com/superfreeeee/Blog-code/tree/main/back_end/rust/rust_drop

上一篇:slab释放调用栈


下一篇:动态内存分配