Rust 学习笔记(27)-Drop trait

参考章节《Rust 程序设计语言》第15.3章 使用 Drop Trait 运行清理代码

对于智能指针模式来说第二个重要的 traitDrop,其允许我们在值要离开作用域时执行一些代码。一些语言也把这个东西叫做 析构函数

Drop trait 要求实现一个叫做 drop 的方法,它获取一个 self 的可变引用。

下面是书上的例子,我觉得有点啰嗦,不过将就看吧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
struct CustomSmartPointer {
    data: String,
}

// 实现 Drop trait
impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data); // 一般我们在这里做清理操作
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };
    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };
    println!("CustomSmartPointers created.");
}

当运行这个程序,输出如下

1
2
3
4
5
6
7
$ cargo run
   Compiling drop-example v0.1.0 (file:///projects/drop-example)
    Finished dev [unoptimized + debuginfo] target(s) in 0.60s
     Running `target/debug/drop-example`
CustomSmartPointers created. 
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!

通过 std::mem::drop 提早丢弃值

有些情况下,你可能需要提前调用 drop,而不是等到它离开作用域时自动调用
比如当使用智能指针管理锁时;你可能希望强制运行 drop 方法来释放锁以便作用域中的其他代码可以获取锁。
不幸的是,Rust 并不允许我们主动调用 Drop traitdrop 方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn main() {
    let c = CustomSmartPointer {
        data: String::from("some data"),
    };
    println!("CustomSmartPointer created.");

    c.drop(); // 这里主动调用 drop 方法

    println!("CustomSmartPointer dropped before the end of main.");
}

当运行这段代码时,会报错

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ cargo run
   Compiling drop-example v0.1.0 (file:///projects/drop-example)
error[E0040]: explicit use of destructor method
  --> src/main.rs:16:7
   |
16 |     c.drop();
   |     --^^^^--
   |     | |
   |     | explicit destructor calls not allowed
   |     help: consider using `drop` function: `drop(c)`

For more information about this error, try `rustc --explain E0040`.
error: could not compile `drop-example` due to previous error

Rust 不允许我们显式调用 drop 因为 Rust 仍然会在 main 的结尾对值自动调用 drop,这会导致一个 double free 错误,因为 Rust 会尝试清理相同的值两次。

为此,我们可以使用 std::mem::drop,不同于 Drop trait 中的 drop 方法。std::mem::drop可以通过传递希望提早强制丢弃的值作为参数。

std::mem::drop 位于 prelude,因此可以直接使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn main() {
    let c = CustomSmartPointer {
        data: String::from("some data"),
    };
    println!("CustomSmartPointer created.");

    drop(c); // 这样就可以了

    println!("CustomSmartPointer dropped before the end of main.");
}

运行这段代码,输出如下

1
2
3
4
5
6
7
$ cargo run
   Compiling drop-example v0.1.0 (file:///projects/drop-example)
    Finished dev [unoptimized + debuginfo] target(s) in 0.73s
     Running `target/debug/drop-example`
CustomSmartPointer created.
Dropping CustomSmartPointer with data `some data`!
CustomSmartPointer dropped before the end of main.

从结果来看,我们调用 drop 提前清理后,在离开作用域后,Rust 就不会再调用 c.drop
但其实不然,当调用 drop 时,我猜这里 c 就已经算离开作用域了,因为 c 的所有权移动到 drop 里了,不过这是我猜的,不过应该我是对的,哈哈哈

updatedupdated2024-10-012024-10-01