patternrustMajor
When I can use either Cell or RefCell, which should I choose?
Viewed 0 times
eitherrefcellshouldusechoosecellwhencanwhich
Problem
From the
When I do have a
Here's a silly, made-up example that uses both
std::cell documentation, I see that Cell is "only compatible with types that implement Copy". This means I must use RefCell for non-Copy types.When I do have a
Copy type, is there a benefit to using one type of cell over another? I assume the answer is "yes", because otherwise both types wouldn't exist! What are the benefits and tradeoffs of using one type over the other?Here's a silly, made-up example that uses both
Cell and RefCell to accomplish the same goal:use std::cell::{Cell,RefCell};
struct ThingWithCell {
counter: Cell,
}
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,
}
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());
}Solution
I think it is important to take into account the other semantic differences between
Let us imagine a situation where these differences matter:
In this case, if we imagine some complex workflow with a lot of callback and that
On the other hand, a similar code using
In this case, any modification of
I would decide which to use depending of the semantics of the value it holds, rather than simply the
Cell and RefCell:Cellprovides you values,RefCellwith references
Cellnever panics,RefCellcan panic
Let us imagine a situation where these differences matter:
let cell = Cell::new(foo);
{
let mut value = cell.get();
// do some heavy processing on value
cell.set(value);
}In this case, if we imagine some complex workflow with a lot of callback and that
cell is part of a global state, it is possible that the contents of cell are modified as a side effect of the "heavy processing", and these potential changes will be lost when value is written back in cell.On the other hand, a similar code using
RefCell:let cell = RefCell::new(foo);
{
let mut_ref = cell.borrow_mut().unwrap();
// do some heavy processing on mut_ref
}In this case, any modification of
cell as a side-effect of the "heavy processing" is forbidden, and would result into a panic. You thus are certain that the value of cell will not change without using mut_refI would decide which to use depending of the semantics of the value it holds, rather than simply the
Copy trait. If both are acceptable, then Cell is lighter and safer than the other, and thus would be preferable.Code Snippets
let cell = Cell::new(foo);
{
let mut value = cell.get();
// do some heavy processing on value
cell.set(value);
}let cell = RefCell::new(foo);
{
let mut_ref = cell.borrow_mut().unwrap();
// do some heavy processing on mut_ref
}Context
Stack Overflow Q#30275982, score: 73
Revisions (0)
No revisions yet.