【Rust自学】15.4. Drop trait:告别手动清理,释放即安全 15.4 Drop trait告别手动清理释放即安全15.4.1Droptrait 的意义如果某个类型实现了Droptrait就可以让程序员自定义值离开作用域时发生的操作。例如释放文件或网络资源。在某些语言中比如 C/C对于某些类型程序员每次用完这些类型的实例时都必须写代码来释放内存或资源。如果忘记了系统可能会过载并崩溃。在 Rust 中程序员可以指定每当值离开作用域时运行的代码编译器会自动插入这段代码。任何类型都可以实现Droptrait而Drop只要求实现drop方法其参数是对self的可变引用。Drop在预导入模块prelude中因此使用时不必手动引入。看个例子struct CustomSmartPointer { data: String, } 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.); }结构体CustomSmartPointer有一个data字段类型为String。通过impl Drop for CustomSmartPointer为CustomSmartPointer实现了Droptrait。在其中实现drop方法参数是mut self。这个方法通常用于释放资源但出于演示目的这里只打印一句话并把self中data字段的内容输出出来。在main中创建了两个CustomSmartPointer实例c存的是my stuffd存的是other stuff。最后打印CustomSmartPointers created.。输出CustomSmartPointers created. Dropping CustomSmartPointer with data other stuff! Dropping CustomSmartPointer with data my stuff!程序会先打印main中println!的内容也就是CustomSmartPointers created.。因为c和d在main结束时离开作用域所以程序会按声明的逆序丢弃它们先d再c。由于这里实现的drop会打印一句话因此这两个值在被丢弃时都会各打印一行。15.4.2 使用std::mem::drop来提前丢弃值比较遗憾的是我们很难直接禁用自动的drop也没必要这么做。因为Droptrait 的目的就是自动处理清理逻辑。此外Rust 不允许手动调用Droptrait 的drop方法。但你可以调用标准库函数std::mem::drop来提前丢弃一个值这相当于提前调用了Drop的drop方法。它的参数就是要丢弃的值。看struct CustomSmartPointer { data: String, } 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), }; drop(c); println!(CustomSmartPointers created.); }在main中我们手动使用drop清理了c而d仍然是自动清理的。输出顺序应该是c在d之前。输出Dropping CustomSmartPointer with data my stuff! CustomSmartPointers created. Dropping CustomSmartPointer with data other stuff!有些人可能会疑问如果c在离开作用域之前就被丢弃了那么离开作用域后编译器会不会再调用一次drop从而导致二次释放double free错误答案是不会。Rust 的设计是安全的。它的所有权系统会保证引用有效而drop也只会在确定不再使用这个值时被调用一次。