从std::cell文档中,我看到Cell"只与实现的类型兼容Copy".这意味着我必须使用RefCell非Copy类型.
当我这样做有一个Copy类型,是否有使用一种类型的细胞在另一个好处?我假设答案是肯定的,因为否则两种类型都不存在!使用一种类型而不是另一种类型有什么好处和权衡?
这是一个愚蠢的,虚构的例子,使用两者Cell并RefCell实现相同的目标:
use std::cell::{Cell,RefCell};
struct ThingWithCell {
counter: Cell<u8>,
}
impl ThingWithCell {
fn new() -> ThingWithCell {
ThingWithCell { counter: Cell::new(0) }
}
fn increment(&self) {
self.counter.set(self.counter.get() + 1);
}
fn count(&self) -> u8 { self.counter.get() }
}
struct ThingWithRefCell {
counter: RefCell<u8>,
}
impl ThingWithRefCell {
fn new() -> ThingWithRefCell {
ThingWithRefCell { counter: RefCell::new(0) }
}
fn increment(&self) {
let mut counter = self.counter.borrow_mut();
*counter = *counter + 1;
}
fn count(&self) -> u8 { *self.counter.borrow_mut() }
}
fn main() {
let cell = ThingWithCell::new();
cell.increment();
println!("{}", cell.count());
let cell = ThingWithRefCell::new();
cell.increment();
println!("{}", cell.count());
}
Run Code Online (Sandbox Code Playgroud)
Lev*_*ans 23
我认为考虑到Cell和之间的其他语义差异很重要RefCell:
Cell为您RefCell提供参考值Cell永远不会恐慌,RefCell可以恐慌让我们想象一下这些差异很重要的情况:
let cell = Cell::new(foo);
{
let mut value = cell.get();
// do some heavy processing on value
cell.set(value);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果我们想象一些具有大量回调的复杂工作流并且cell是全局状态的一部分,则可能将内容cell修改为"重处理"的副作用,并且这些潜在的改变将是value写回时丢失了cell.
另一方面,类似的代码使用RefCell:
let cell = RefCell::new(foo);
{
let mut_ref = cell.borrow_mut().unwrap();
// do some heavy processing on mut_ref
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,任何cell对"重处理"的副作用的修改都是被禁止的,并且会导致恐慌.因此,您可以确定,cell如果不使用,价值就不会改变mut_ref
我将决定使用哪个取决于它所持有的值的语义,而不仅仅是Copy特征.如果两者都是可接受的,则Cell比另一种更轻且更安全,因此是优选的.
blu*_*uss 15
Cell如果可以,你应该使用.
Cell根本不使用运行时检查.它所做的只是一个不允许别名的封装,并告诉编译器它是一个内部可变的插槽.在大多数情况下,它应编译为与没有单元格包装的类型完全相同的代码.
相比之下,RefCell使用简单的使用计数器来检查借用与运行时的可变借用,如果违反了可变借用的排他性,那么检查可能会导致运行时出现恐慌.可能的恐慌可能是优化的障碍.
至少还有一个区别.A Cell永远不会让你得到一个指向存储值本身的指针.所以,如果你需要,a RefCell是唯一的选择.
TL; DR:Cell如果可以的话。
长答案:Cell并RefCell具有类似的名称,因为它们都允许内部可变性,但是它们具有不同的用途:
Cell它是一个包装程序T,禁止一次共享多次:您不能一成不变地借用内部数据。该包装器没有任何开销,但是由于此限制,您只能执行以下操作:
T是Copy能,因而)。由于其局限性,Cell行为就像独占借名,也称为 a &mut T。因此,更改内部值始终是安全的。总结一下:
RefCell它是围绕一个包装T该“清除”编译时借位检查:用于修改所述内值取一个共享参照的操作&self的RefCell。通常,这是不安全的,但是每个修改操作首先都会验证该值先前是否未被借用。在运行时验证可变借位的排他性。
总结一下:
优势和局限是彼此的镜像。您的问题的答案是:如果您的限制Cell不打扰您,请使用它,因为除此之外,它仅具有优势。但是,如果您想要更灵活的内部可变性,请使用RefCell。
| 归档时间: |
|
| 查看次数: |
6294 次 |
| 最近记录: |