Trait std::ops::Drop1.0.0[][src]

pub trait Drop {
    fn drop(&mut self);
}
Expand description

析构函数中的自定义代码。

当不再需要某个值时,Rust 将对该值运行 “析构函数”。 不再需要值的最常见方法是离开作用域。析构函数可能仍在其他情况下运行,但是在这里的示例中,我们将重点关注作用域。 要了解其他一些情况,请参见析构函数的 the reference 部分。

此析构函数由两个组件组成:

  • 如果为此类型实现了特殊的 Drop trait,则对该值调用 Drop::drop
  • 自动生成的 “drop glue” 递归调用该值的所有字段的析构函数。

由于 Rust 自动调用所有包含字段的析构函数,因此在大多数情况下,您无需实现 Drop。 但是在某些情况下它很有用,例如对于直接管理资源的类型。 该资源可能是内存,可能是文件描述符,可能是网络套接字。 一旦不再使用该类型的值,则应通过释放内存或关闭文件或套接字 “clean up” 资源。 这是析构函数的工作,因此也是 Drop::drop 的工作。

Examples

要查看析构函数的作用,让我们看一下以下程序:

struct HasDrop;

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

struct HasTwoDrops {
    one: HasDrop,
    two: HasDrop,
}

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

fn main() {
    let _x = HasTwoDrops { one: HasDrop, two: HasDrop };
    println!("Running!");
}
Run

Rust 将首先为 _x 调用 Drop::drop,然后为 _x.one_x.two 调用,这意味着运行此命令将打印

Running!
Dropping HasTwoDrops!
Dropping HasDrop!
Dropping HasDrop!

即使我们删除了针对 HasTwoDropDrop 的实现,其字段的析构函数仍然会被调用。 这将导致

Running!
Dropping HasDrop!
Dropping HasDrop!

您不能自己调用 Drop::drop

因为 Drop::drop 是用来清理一个值的,所以在调用方法后使用该值可能很危险。 由于 Drop::drop 不拥有其输入的所有权,因此 Rust 通过不允许您直接调用 Drop::drop 来防止误用。

换句话说,如果您在上面的示例中尝试显式调用 Drop::drop,则会出现编译器错误。

如果您想显式调用一个值的析构函数,可以使用 mem::drop 代替。

Drop 指令

但是,我们的两个 HasDrop 哪个先丢弃掉? 对于结构体,其声明顺序相同: 首先是 one,然后是 two。 如果您想自己尝试一下,可以修改上面的 HasDrop 以包含一些数据 (例如整数),然后在 Drop 内部的 println! 中使用它。 此行为由语言保证。

与结构体不同,局部变量以相反的顺序丢弃:

struct Foo;

impl Drop for Foo {
    fn drop(&mut self) {
        println!("Dropping Foo!")
    }
}

struct Bar;

impl Drop for Bar {
    fn drop(&mut self) {
        println!("Dropping Bar!")
    }
}

fn main() {
    let _foo = Foo;
    let _bar = Bar;
}
Run

这将打印

Dropping Bar!
Dropping Foo!

有关完整规则,请参见 the reference

CopyDrop 是互斥的

您不能在同一类型上同时实现 CopyDropCopy 类型被编译器隐式复制,这使得很难预测何时以及将执行析构函数的频率。

因此,这些类型不能有析构函数。

Required methods

执行此类型的析构函数。

当值离开作用域时隐式调用此方法,并且不能显式调用此方法 (会得到编译器 E0040 错误)。 但是,prelude 中的 mem::drop 函数可用于调用参数的 Drop 实现。

当这个方法被调用时,self 还没有被释放。 只有在方法结束后才会发生这种情况。 如果不是这种情况,那么 self 将是悬垂引用。

Panics

考虑到 panic! 在展开时将调用 drop,因此 drop 实现中的任何 panic! 都可能会终止。

请注意,即使此 panics,该值也被视为已丢弃; 您不得再次调用 drop。 这通常由编译器自动处理,但是在使用不安全的代码时,有时可能会无意间发生,尤其是在使用 ptr::drop_in_place 时。

Implementors

按堆顺序删除堆元素。

丢弃 Rc

这将减少强引用计数。 如果强引用计数达到零,那么唯一的其他引用 (如果有) 是 Weak,因此我们将 drop 作为内部值。

Examples

use std::rc::Rc;

struct Foo;

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

let foo  = Rc::new(Foo);
let foo2 = Rc::clone(&foo);

drop(foo);    // 不打印任何东西
drop(foo2);   // 打印 "dropped!"
Run

丢弃 Weak 指针。

Examples

use std::rc::{Rc, Weak};

struct Foo;

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

let foo = Rc::new(Foo);
let weak_foo = Rc::downgrade(&foo);
let other_weak_foo = Weak::clone(&weak_foo);

drop(weak_foo);   // 不打印任何东西
drop(foo);        // 打印 "dropped!"

assert!(other_weak_foo.upgrade().is_none());
Run

丢弃 Arc

这将减少强引用计数。 如果强引用计数达到零,那么唯一的其他引用 (如果有) 是 Weak,因此我们将 drop 作为内部值。

Examples

use std::sync::Arc;

struct Foo;

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

let foo  = Arc::new(Foo);
let foo2 = Arc::clone(&foo);

drop(foo);    // 不打印任何东西
drop(foo2);   // 打印 "dropped!"
Run

丢弃 Weak 指针。

Examples

use std::sync::{Arc, Weak};

struct Foo;

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

let foo = Arc::new(Foo);
let weak_foo = Arc::downgrade(&foo);
let other_weak_foo = Weak::clone(&weak_foo);

drop(weak_foo);   // 不打印任何东西
drop(foo);        // 打印 "dropped!"

assert!(other_weak_foo.upgrade().is_none());
Run