Rust标准库的文档指出Cell
只能用于Copy
类型,而在所有其他情况下,应该使用RefCell
,但不能解释原因。
在研究了Cell
和RefCell
的文档和代码之后,唯一重要的一点是get
的{{1}}函数。如果值是Cell
类型,则可以返回此类副本。但为什么克隆不够好呢?
可以在Copy
:
set
功能
RefCell
只有在没有其他人持有对该值的引用时,这才有效。但是,如果可以克隆该值,可以这样做:
fn set<T>(r: &RefCell<T>, v: T) {
*r.borrow_mut() = v
}
使用类似fn get<T: Clone>(r: &RefCell<T>) -> T {
r.borrow().clone()
}
的类型处理Cell
类型可以避免运行时借用检查的开销。我在这里错过了什么吗?
答案 0 :(得分:10)
它不健全。 DK的评论。是在正确的轨道上,但你甚至不需要恐慌造成破坏。一个有问题的情况是:
Option
一起)允许创建循环,即自引用类型Clone
实施获得&self
参考Clone
实现可以访问正在克隆的单元格&self
)Result<T, E>
字段最初为Ok(T)
,请引用内部的T
并使用Result
覆盖Err(R)
。然后&T
突然引用E
值。此示例的信用转到Huon Wilson,请参阅user.rust-lang.org帖子Why does Cell require Copy instead of Clone?。他的文章涉及更多结构性原因,包括一个完整的代码示例。
答案 1 :(得分:2)
这是我的意见,但我不能直接将其与存在这种限制的真正原因联系起来。
我认为副本为&#34;廉价&#34; (例如复制一些比特)和克隆作为&#34;昂贵的&#34; (例如,进行函数调用或更改数据)。如果这样的单元格使用Clone
,它将强制在每次使用时复制基础值(cell.get()
)。例如,使用CloneCell<Vec<T>>
意味着每个cell.get()
都需要调用内存分配器。这不是一个好主意。
因此限制Copy
类型可能是引导人们远离脚部射击的一种方式。
答案 2 :(得分:0)
接受的答案仍然完全正确(并且引人入胜),但我想提一下 Cell
在 Rust 1.17 中获得的一些额外工具,它们不需要内容为 Copy
:
Cell::swap
交换两个单元格的内容。Cell::replace
将新值放入单元格并返回旧值。Cell::take
类似于 replace
,使用 Default::default()
值。注意这里与 mem::swap
、mem::replace
和 mem::take
的接近平行。 (尽管实际上最后一个直到 Rust 1.40 才稳定下来。)Cell
方法有效地执行相同的操作,但它们通过共享引用而不是需要可变引用来工作。
对于实现 Default
的类型,我们可以使用 Cell::take
来完成与 .clone()
非常相似的事情,只需多几个步骤:
fn clone_from_cell<T>(cell: &Cell<T>) -> T
where
T: Clone + Default,
{
let val: T = cell.take();
let clone: T = val.clone();
cell.set(val);
clone
}
对于实现 Clone
但不实现 Default
的类型(有点不常见,但例如 NonZeroU32
),请注意 Option<T>
实现 Default
而不管 { {1}},所以 T
可以通过这种方式“克隆”到任何 Cell<Option<T>>
。
T