تغییرپذیری داخلی
در برخی موقعیتها، لازم است که دادههای پشت یک ارجاع اشتراکی (فقط خواندنی) را تغییر دهید. به عنوان مثال، یک ساختار داده اشتراکی ممکن است دارای یک کش داخلی باشد و بخواهد این کش را از روشهای خواندنی بهروزرسانی کند.
الگوی “تغییرپذیری داخلی” (interior mutability) اجازه میدهد که دسترسی انحصاری (قابل تغییر) پشت یک ارجاع اشتراکی وجود داشته باشد. کتابخانه استاندارد روشهای متعددی برای انجام این کار فراهم میکند، در حالی که همچنان ایمنی را تضمین میکند، معمولاً با انجام یک بررسی در زمان اجرا.
Cell
Cell wraps a value and allows getting or setting the value using only a shared reference to the Cell. However, it does not allow any references to the inner value. Since there are no references, borrowing rules cannot be broken.
use std::cell::Cell; fn main() { // Note that `cell` is NOT declared as mutable. let cell = Cell::new(5); cell.set(123); println!("{}", cell.get()); }
RefCell
RefCell allows accessing and mutating a wrapped value by providing alternative types Ref and RefMut that emulate &T/&mut T without actually being Rust references.
این type با استفاده از یک شمارنده در RefCell بررسیهای dynamic را انجام میدهند تا از وجود RefMut در کنار Ref/RefMut دیگر جلوگیری کنند.
با پیادهسازی Deref (و DerefMut برای RefMut)، این تایپها امکان فراخوانی متدها روی مقدار داخلی را بدون اجازه خروج ارجاعها فراهم میکنند.
use std::cell::RefCell; fn main() { // Note that `cell` is NOT declared as mutable. let cell = RefCell::new(5); { let mut cell_ref = cell.borrow_mut(); *cell_ref = 123; // This triggers an error at runtime. // let other = cell.borrow(); // println!("{}", *other); } println!("{cell:?}"); }
مهمترین نکتهای که باید از این اسلاید برداشت کرد این است که Rust روشهای ایمن برای تغییر دادههای پشت یک ارجاع اشتراکی ارائه میدهد. راههای مختلفی برای تضمین این ایمنی وجود دارد، و RefCell و Cell دو مورد از آنها هستند.
-
RefCellقوانین معمول ارجاع Rust (یا چندین ارجاع اشتراکی یا یک ارجاع انحصاری) را با یک بررسی در زمان اجرا اعمال میکند. در این حالت، همه ارجاعات بسیار کوتاه هستند و هرگز همپوشانی ندارند، بنابراین بررسیها همیشه موفقیتآمیز هستند.- بلوک اضافی در مثال
RefCellبرای پایان دادن به ارجاعی که توسط فراخوانیborrow_mutایجاد شده است، قبل از چاپcellاست. تلاش برای چاپ یکRefCellکه در حال حاضر ارجاع داده شده است، فقط پیغام"{borrowed}"را نشان میدهد.
- بلوک اضافی در مثال
-
Cellیک روش سادهتر برای تضمین ایمنی است: این نوع دارای متدی به نامsetاست کهself&را میپذیرد. این روش نیاز به بررسی در زمان اجرا ندارد، اما نیاز به انتقال مقادیر دارد که میتواند هزینههای خود را داشته باشد. -
هر دو
RefCellوCellدارای!Syncهستند، به این معنی کهRefCell&و&Cellنمیتوانند بین نخها منتقل شوند. این امر مانع از دسترسی همزمان دو نخ به سلول میشود.