Drop为什么选择自我而不是自我?

时间:2015-06-18 03:05:55

标签: rust

为什么Drop的方法有签名Aggregation : CONCAT, COUNT, SUM, MAX, MIN, AVG, MEDIAN, MODE, INDEXOF_MAX, INDEXOF_MIN Comparison : =,>,<, LIKE/NOT LIKE, NULL/NOT NULL, IN/NOT IN, Dates comparison Boolean operators : AND,OR,NOT,XOR 而不是Band/Range JOIN, Self JOIN Views (Temporary files?), Difference/Except, Division Sub-queries/Nested queries Contingency tables ?这使得难以将值移出字段,例如self.join_handle.join()fn drop(&mut self)(错误:无法移出定义fn drop(self)特征的std::mem::drop(self.file)类型。

3 个答案:

答案 0 :(得分:14)

让我们看一下std::mem::drop的实施方式:

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

这是对的:这是一个空功能!那是因为它利用移动语义来获得其参数的所有权。如果T实现Drop,编译器会自动在函数末尾插入对Drop::drop(_x)的调用。这会发生在按值接收的所有参数上(实际上,所有参数,但删除引用不会丢弃引用)。

现在考虑如果Drop::drop通过值获取其参数会发生什么:编译器会尝试在Drop::drop内的参数上调用Drop::drop - 这会导致堆栈溢出!当然,您可以在参数上调用mem::drop,该参数也会尝试以递归方式调用Drop::drop

答案 1 :(得分:6)

实际上,Drop::drop不必拥有该值的所有权。

在Rust中,所有权在语言级别自动处理,因此编译确保正确实现所有权语义;因此,当Foo { a: int, b: String }超出范围时,编译器将通过自动删除其内部字段来删除Foo

因此Drop::drop无需删除字段!

实际上,在Drop::drop上调用 Foo之后的,编译器本身会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. 删除矢量所持有的每个元素
  2. 取消分配内存

答案 2 :(得分:1)

尽管上面有很好的答案,但我仍然需要澄清。这就是我得到的......

Drop trait,

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

需要 mutable reference 而不是 move,因为 drop 函数不是为了释放内存而只是在发布之前执行准备工作。因此,drop 函数的更好名称可能是 prepare_to_drop

实际的内存释放由std::mem模块中的一个函数执行,定义如下:

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

正如预期的那样,它显然使用了编译器生命周期管理语义。如果我们假设编译器隐式地为所有没有实现自己的类型派生了一个空的 Drop 特征,那么这个特定函数的一个更具启发性的编码揭示了编译器的体操......

pub fn drop<T: Drop>(x: T) { //this is a bare function (no Self)
    x.drop();
}

最后,Drop trait 需要 mutable reference, &mut T 而不是 shared reference, &T 的原因是准备工作可能包括改变 {{ 1}},例如移出内容、在 T 上不允许的操作。