rust 为什么Drop使用&mut self而不是self?

wj8zmpe1  于 2023-03-30  发布在  其他
关注(0)|答案(2)|浏览(139)

为什么Drop的方法有签名fn drop(&mut self)而不是fn drop(self)?这使得很难将值移出字段,例如self.join_handle.join()std::mem::drop(self.file)(错误:不能移出类型X,它定义了Drop trait)。

92dk7w1h

92dk7w1h1#

让我们看看std::mem::drop是如何实现的:

pub fn drop<T>(_x: T) { }

没错这是一个空函数!这是因为它利用了move语义来获取其参数的所有权。如果T实现了Drop,编译器会自动在函数的末尾插入一个对Drop::drop(_x)的调用。这会发生在所有通过value接收的参数上(也就是说,实际上,* 所有 * 参数,但删除引用并不会删除referent)。
现在考虑一下如果Drop::drop通过值获取参数会发生什么:编译器会尝试调用Drop::drop中的参数Drop::drop-这会导致堆栈溢出!当然,你可以调用参数mem::drop,它也会尝试递归调用Drop::drop

cbwuti44

cbwuti442#

实际上,Drop::drop没有必要取得该值的所有权。
在Rust中,所有权在语言级别自动处理,因此编译器确保正确实现所有权语义;因此,当Foo { a: int, b: String }超出范围时,编译器将通过自动删除其内部字段来删除Foo
因此,Drop::drop没有必要删除字段!
实际上,* 在Foo上调用 * Drop::drop之后,编译器将自己mem::drop不同的字段(也可能在定义它的字段上调用Drop::drop,例如这里的b: String)。
Drop::drop是什么意思
它用于在编译器将要做的事情之上实现 * 额外的 * 逻辑;以JoinHandle为例:

#[stable(feature = "rust1", since = "1.0.0")]
#[unsafe_destructor]
impl<T> Drop for JoinHandle<T> {
    fn drop(&mut self) {
        if !self.0.joined {
            unsafe { imp::detach(self.0.native) }
        }
    }
}

例如,这里使用Drop::drop来分离线程。
Vec::vec这样的集合中:

#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Vec<T> {
    fn drop(&mut self) {
        // This is (and should always remain) a no-op if the fields are
        // zeroed (when moving out, because of #[unsafe_no_drop_flag]).
        if self.cap != 0 && self.cap != mem::POST_DROP_USIZE {
            unsafe {
                for x in &*self {
                    ptr::read(x);
                }
                dealloc(*self.ptr, self.cap)
            }
        }
    }
}

在这里,由于原始内存是以编译器不透明的方式操作的,因此该实现负责:
1.删除vector中的每个元素
1.释放内存

相关问题