rust - Situations where Cell or RefCell is the best choice -
when required use cell or refcell? seems there many other type choices suitable in place of these, , documentation warns using refcell
bit of "last resort".
is using these types "code smell"? can show example using these types makes more sense using type, such rc
or box
?
it not entirely correct ask when cell
or refcell
should used on box
, rc
because these types solve different problems. indeed, more not refcell
used together rc
in order provide mutability shared ownership. yes, use cases cell
, refcell
entirely dependent on mutability requirements in code.
interior , exterior mutability nicely explained in official rust book, in designated chapter on mutability. external mutability closely tied ownership model, , when mutable or immutable mean external mutability. name external mutability inherited mutability, explains concept more clearly: kind of mutability defined owner of data , inherited can reach owner. example, if variable of structural type mutable, fields of structure in variable:
struct point { x: u32, y: u32 } // variable mutable... let mut p = point { x: 10, y: 20 }; // ...and fields reachable through variable p.x = 11; p.y = 22; let q = point { x: 10, y: 20 }; q.x = 33; // compilation error
inherited mutability defines kinds of references can value:
{ let px: &u32 = &p.x; // okay } { let py: &mut u32 = &mut p.x; // okay, because p mut } { let qx: &u32 = &q.x; // okay } { let qy: &mut u32 = &mut q.y; // compilation error since q not mut }
sometimes, however, inherited mutability not enough. canonical example reference-counted pointer, called rc
in rust. following code entirely valid:
{ let x1: rc<u32> = rc::new(1); let x2: rc<u32> = x1.clone(); // create reference same data let x3: rc<u32> = x2.clone(); // } // here references destroyed , memory pointing @ deallocated
at first glance not clear how mutability related this, recall reference-counted pointers called because contain internal reference counter modified when reference duplicated (clone()
in rust) , destroyed (goes out of scope in rust
). hence rc
has modify though stored inside non-mut
variable.
this achieved via internal mutability. there special types in standard library, basic of them being unsafecell
, allow 1 work around rules of external mutability , mutate if stored (transitively) in non-mut
variable.
another way has internal mutability can modified through &
-reference - is, if have value of type &t
, can modify state of t
points at, t
has internal mutability.
for example, cell
can contain copy
data , can mutated if stored in non-mut
location:
let c: cell<u32> = cell::new(1); c.set(2); assert_eq!(c.get(), 2);
refcell
can contain non-copy
data , can give &mut
pointers contained value, , absence of aliasing checked @ runtime. explained in detail on documentation pages.
as turned out, in overwhelming number of situations can go external mutability only. of existing high-level code in rust written way. sometimes, however, internal mutability unavoidable or makes code clearer. 1 example, rc
implementation, described above. 1 when need shared mutable ownership (that is, need access , modify same value different parts of code) - achieved via rc<refcell<t>>
, because can't done references alone. example arc<mutex<t>>
, mutex
being type internal mutability safe use across threads.
so, can see, cell
, refcell
not replacements rc
or box
; solve task of providing mutability somewhere not allowed default. can write code without using them @ all; , if situation when need them, know it.
cell
s , refcell
s not code smell; reason whey described "last resort" move task of checking mutability , aliasing rules compiler runtime code, in case refcell
: can't have 2 &mut
s pointing same data @ same time, statically enforced compiler, refcell
s can ask same refcell
give &mut
s - except if more once panic @ you, enforcing aliasing rules @ runtime. panics arguably worse compilation errors because can find errors causing them @ runtime rather @ compilation time. sometimes, however, static analyzer in compiler restrictive, , indeed need "work around" it.
Comments
Post a Comment