为什么 Rust 中的 Cell 只能用于 Copy 而不是 Clone 类型? [英] Why can Cell in Rust only be used for Copy and not Clone types?

查看:84
本文介绍了为什么 Rust 中的 Cell 只能用于 Copy 而不是 Clone 类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Rust 标准库的文档声明 Cell 只能用于 Copy 类型,在所有其他情况下应该使用 RefCell,但没有解释确切原因.

The documentation of the Rust standard library states that Cell can be only used for Copy types and that in all other cases one should use RefCell, but does not explain exactly why.

在研究了 CellRefCell 的文档和代码后,唯一看起来很重要的地方是 get 函数Cell.如果值是 Copy 类型,则可以返回这样的副本.但为什么克隆不够好?

After studying the documentation and the code of both Cell and RefCell, the only point where it seems to be important is the get function of Cell. If the value is a Copy type then one can just return such a copy. But why is a clone not good enough?

可以直接在RefCell之上实现set函数:

One could directly implement the set function on top of RefCell:

fn set<T>(r: &RefCell<T>, v: T) {
    *r.borrow_mut() = v
}

这仅在没有其他人持有对该值的引用时才有效.但是如果可以克隆值,就可以这样做:

This only works as long as no one else is holding a reference to the value. But if the value can be cloned, one can just do that:

fn get<T: Clone>(r: &RefCell<T>) -> T {
    r.borrow().clone()
}

让像 Cell 这样的类型与 Clone 类型一起工作将避免运行时借用检查的开销.我在这里遗漏了什么吗?

Having a type like Cell working with Clone types would avoid the overhead of the run-time borrow checking. Am I missing anything here?

推荐答案

它不健全.DK的评论.是在正确的轨道上,但您甚至不需要恐慌就可以造成严重破坏.一个有问题的场景是这样的:

It's unsound. The comment by DK. is on the right track but you don't even need a panic to cause havoc. One problematic scenario is this:

  1. 单元格(与 Option 一起)允许创建循环,即自引用类型
  2. Clone 实现获得一个 &self 引用
  3. 在存在循环的情况下,Clone 实现可能因此访问被克隆的单元
  4. 因此被克隆的对象可以覆盖自身,而它对自身有一个普通的借用(即,&self)
  5. 在借用时覆盖是不合理的,因为它允许任意类型的双关语和其他坏处.例如,假设有 Result 字段最初是 Ok(T),引用里面的 T 并覆盖Result 带有 Err(R).然后 &T 突然引用了一个 E 值.
  1. Cells (together with Option) allow creating cycles, i.e., self-referential types
  2. The Clone implementation gets a &self reference
  3. In the presence of a cycle, the Clone implementation may thus access the cell that's being cloned
  4. Therefore the object being cloned can overwrite itself, while it has an ordinary borrow to itself (namely, &self)
  5. Overwriting while borrowing is unsound because it allows arbitrary type punning and other badness. For example, suppose there's Result<T, E> field that's initially Ok(T), take a reference to the T inside and overwrite the Result with an Err(R). Then the &T suddenly refers to an E value.

此示例归功于 Huon Wilson,请参阅 user.rust-lang.org 主题 为什么 Cell 需要复制而不是克隆?.他的文章深入探讨了限制的更多结构性原因,还包括一个完整的代码示例.

Credit for this example goes to Huon Wilson, see the user.rust-lang.org thread Why does Cell require Copy instead of Clone?. His write-up goes into more structural reasons for the restrictions and includes a complete code example, too.

这篇关于为什么 Rust 中的 Cell 只能用于 Copy 而不是 Clone 类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆