分类

Rust 中的 Drop Trait

2019-08-10 16:08 rust

Drop Trait

先看代码:

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

#[derive(Default)]
struct Rectangle {
    pub p1: Point,
    pub p2: Point,
}

impl Drop for Point {
    fn drop(&mut self) {
        println!("Point {} {} ::drop()", self.x, self.y);
    }
}

impl Drop for Rectangle {
    fn drop(&mut self) {
        println!("Rectangle::drop()");
    }
}

fn main() {
    let _p = Point::default();
    let _r = Rectangle {
        p1: Point { x: 1, y: 2 },
        p2: Point { x: 3, y: 4 },
    };
}

打印的结果是:

Rectangle::drop()
Point 1 2 ::drop()
Point 3 4 ::drop()
Point 0 0 ::drop()

可以发现 Drop Trait 的几个特性:

  • Drop::drop() 方法是被隐式调用的.
  • 先调用了 Rectangle::drop(), 之后调用了其内部属性的 Point::drop().
  • Rectangle 内部性性的 drop() 方法是基于声明的先后顺序调用的. 上面才会先打印 Point 1 2 ::drop(), 再打印 Point 3 4 ::drop().
  • 先声明的变量后被 drop. 上面的试验, 先 drop 了 Rectangle _r, 之后再 drop 了 Point _p.

另外还有几个特点:

  • Drop::drop() 是不能手动调用的.
  • Drop trait 只能用于结构体 (struct), 不能用于 primative type.

mem::drop

尽管不能手动调用 Drop::drop() 方法来 destruct 一个结构体, 但我们可以调用 std::mem::drop() 函数, 这个函数的实现也是非常简单的.

#[inline]
fn drop(_x: T) { }

它获取了传入参数的所有权, 然后什么都不做, 等该函数运行完之后, 该变量 _x 的值 的生命周期已完成, 它就要被释放掉.

我们来修改一下上面的测试代码:


fn main() {
    let p = Point::default();
    let _r = Rectangle {
        p1: Point { x: 1, y: 2 },
        p2: Point { x: 3, y: 4 },
    };

    std::mem::drop(p);
}

这次的打印结果是:

Point 0 0 ::drop()
Rectangle::drop()
Point 1 2 ::drop()
Point 3 4 ::drop()

Point p 优先被 drop 了, 因为 std::mem::drop(p); 这条调用完结之后, Point p 的生命周期就完结了. 之后, 在 main() 函数结束时, 自动调用了 Rectangle _rdrop() 方法.

关于 mem::drop() 有一点要注意的是, 它只能用来 drop 没有实现 Copy trait 的变量, 像 rust 里的原始数据类型, usize/u8/u16/u32/u64/u128/... 这些都是实现了 Copy trait的, mem::drop() 来 drop 它们时, 是没有效果的. 比如下面的代码, 变量 x 在传入 drop() 函数时, 它的值是被复制了一份的, 所以并不能 drop 变量 x 本身.

let x = 42;
std::mem::drop(x);