Rust 中的 `Cell` 可以安全地用于 `Rc` 吗?

Could `Cell` in Rust be safely used on `Rc` specifically?

已经确定(例如在 中)Rust 的 Cell 不适用于非 Copy 类型,因为 .get() 操作只有在可以保证 cloning/copying 从 Cell 出来的数据不会被分配给 Cell.

的东西打断

因此,Rust 中的当前限制是 Cell.get() 仅在单元格内的类型为 Copy 时可用; Clone 是不够的,因为不能保证 .clone() 调用不会以某种方式设法访问正在克隆的 Cell 并在它处于中间时写入它被阅读。所以像这样的代码是非法的,因为编译器不确定 CloneableObject.clone() 不会做一些荒谬的事情:

use std::cell::Cell;
#[derive(Debug, Clone)]
struct CloneableObject {}

fn main() {
    let x = Cell::new(CloneableObject {});
    println!("{:?}", x.get());
}

我的问题是关于 Cell 包装的类型是标准库类型 Rc 的特殊情况。 Rc 的特殊之处在于 Rc.clone() 实际上不进行任何复制,也不检查 Rc 指向的值;它只是在 Rc 中递增一个整数,这不可能写入包含 Rc.

Cell

据推测,这意味着像下面这样的代码可以安全地合法:

use std::cell::Cell;
use std::rc::Rc;

fn main() {
    let x = Cell::new(Rc::new(0i32));
    println!("{:?}", x.get());
}

但是目前编译不了,因为CellRc没有特例。

我的问题是:是否有任何 safety/soundness 理由不为 Cell<Rc<T>> 添加这种特殊情况?或者这仅仅是“这将是完全安全的,但我们还没有教编译器如何识别它是安全的”的情况? (如果这样做 是安全的,我可以将其作为功能建议提交—​​—由于不需要运行时检查,它会比 RefCell<Rc<T>> 更有效——但我想确保我没有遗漏任何不健全的地方。)

为了避免混淆:我在这个问题中故意问的是Cell<Rc<T>>,而不是更常用的Rc<Cell<T>>/Rc<RefCell<T>>.

是的,它可能可以,但在目前的状态下,Rust 缺乏表明这一点所需的专业化功能。

理论上,可能有一个特征表明可以安全地从 Cell::get:

克隆一个类型
use std::cell::UnsafeCell;
use std::rc::Rc;

pub struct Cell<T> {
    inner: UnsafeCell<T>,
}

impl<T> Cell<T> {
    pub fn set(&self, value: T) {
        unsafe { *self.inner.get() = value };
    }

    pub fn get(&self) -> T
    where
        T: CellCloneable,
    {
        unsafe { *self.inner.get() }.clone()
    }
}

trait CellCloneable: Clone {}
impl<T> CellCloneable for T where T: Copy {}
impl<T> CellCloneable for Rc<T> {}

不幸的是,由于缺乏专业化功能,这也无法编译。

并且由于编译器无法保证实现者不会最终调用 Cell::set 自身,因此它必须是 unsafe 特征。这个特性很容易出错:任何动态调度都会使这个安全约束无法保证,并且不相关的代码可以更新以违反这个约束而不使用任何 unsafe 本身。

IMO,这一添加将违背 Cell 的目标,即成为内部可变性的相当基本和安全的原语。