为什么在 Rust 的 `Cell<T>` 中,`set` 方法明确丢弃旧值?

14

为什么在Cell上定义的set方法,在最后一行明确地删除了old值?难道函数返回时不会自动释放内存吗?

use std::mem;
use std::cell::UnsafeCell;

pub struct Cell<T> {
    value: UnsafeCell<T>
}

impl<T> Cell<T> {
    pub fn set(&self, val: T) {
        let old = self.replace(val);
        drop(old); // Is this needed?
    } // old would drop here anyways?
    
    pub fn replace(&self, val: T) -> T {
        mem::replace(unsafe { &mut *self.value.get() }, val)
    }
}

那么为什么不让 set 只执行这个操作呢:
pub fn set(&self, val: T) {
    self.replace(val);
}

或者std::ptr::read执行了我不理解的操作。
1个回答

10

调用 drop 并非必须的,但在某些情况下可以帮助代码更易于阅读。如果我们只是调用 replace,代码看起来就像是对 replace 的一层包装函数,读者可能会失去上下文中它执行了一个额外的操作(删除先前的值)。尽管到最后使用哪个版本有些主观性,并且没有任何实际区别。

话虽如此,其实真正的原因是在设置值时它并不总是删除之前的值。以前,Cell<T> 实现了通过不安全指针操作覆盖现有值的 set 方法。后来在rust-lang/rust#39264: Extend Cell to non-Copy types 中进行了修改,以便始终删除先前的值。作者(wesleywiser)可能希望更明确地显示当向单元格写入新值时先前的值将被删除,以便审核请求更加方便。

个人认为,在这种情况下使用 drop 是很好的,因为它有助于传达我们打算如何处理 replace 方法的结果。


2
此外,在调试构建中,如果出现 panic,则具有两个不同的源代码行号可能有助于确定原因。虽然我不认为 replace 可能会 panic。 - rodrigo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接