
روز ۱۳: Borrowing و References در Rust
بعد از یادگیری مفاهیم Ownership، Move و Copy، یکی از مهمترین مفاهیم Rust که در روز سیزدهم بررسی میکنیم، Borrowing و References است. این دو مفهوم به برنامهنویس امکان میدهند بدون انتقال Ownership، به دادهها دسترسی داشته باشد و همزمان ایمنی حافظه حفظ شود. Borrowing و References پایهای برای نوشتن برنامههای Rust حرفهای هستند و به شما کمک میکنند توابع و ساختارهای دادهای پیچیده را بدون از دست دادن کنترل Ownership مدیریت کنید. Rust با طراحی دقیق این ویژگیها تضمین میکند که هیچ دادهای در حال استفاده، آزاد نشود و هیچ باگ حافظهای ایجاد نشود.
Borrowing به معنای قرض گرفتن دادهها است و به برنامهنویس اجازه میدهد یک مقدار را بدون مالکیت آن استفاده کند. وقتی یک مقدار Borrow میشود، مالک اصلی همچنان مسئول مدیریت حافظه است و داده پس از پایان Borrowing به مالک اصلی باز میگردد. Rust با بررسی Borrowing در زمان کامپایل، اطمینان حاصل میکند که هیچ دادهای در زمان استفاده آزاد یا تغییر نمیکند و قوانین ایمنی حافظه نقض نمیشوند. این سیستم باعث میشود توسعهدهنده بدون نگرانی از مشکلات رایج حافظه، کد امن و بهینه بنویسد.
References و انواع آنها در Rust
در Rust، Borrowing معمولاً با استفاده از References انجام میشود. References به دو نوع اصلی تقسیم میشوند: immutable و mutable. یک Reference immutable تنها اجازه مشاهده دادهها را میدهد و نمیتوان آنها را تغییر داد، در حالی که یک Reference mutable اجازه تغییر دادهها را فراهم میکند اما محدودیتهای سختگیرانهای دارد. Rust تضمین میکند در یک زمان فقط یک mutable Reference یا چندین immutable Reference به یک داده وجود داشته باشد تا از مشکلات همزمانی و شرایط مسابقه جلوگیری شود.
استفاده از References باعث میشود کدها خواناتر و امنتر باشند و توسعهدهنده بتواند دادهها را بدون ایجاد Move یا Copy اضافی به توابع منتقل کند. این ویژگی به خصوص برای دادههای بزرگ یا ساختارهای پیچیده بسیار مفید است، زیرا عملکرد برنامه حفظ میشود و حافظه بهینه مصرف میشود. علاوه بر این، سیستم Borrowing و References باعث میشود برنامههای Rust بسیار قابل پیشبینی و کمخطا باشند، حتی در پروژههای بزرگ و تیمی.
let s = String::from("Hello");
let len = calculate_length(&s);
fn calculate_length(s: &String) -> usize {
s.len()
}در این مثال، متغیر s به تابع calculate_length بهصورت Reference قرض داده شده و Ownership آن منتقل نمیشود. پس از اجرای تابع، s همچنان معتبر و قابل استفاده باقی میماند.
Borrowing mutable و قوانین Rust
Mutable Borrowing به شما اجازه میدهد مقدار یک داده را بدون انتقال Ownership تغییر دهید، اما Rust قوانین سختگیرانهای برای جلوگیری از همزمانی و خطاهای حافظه اعمال میکند. تنها یک mutable Reference در یک زمان میتواند وجود داشته باشد و نمیتوان همزمان immutable Reference داشت. این قوانین باعث میشود دادهها همیشه تحت کنترل باشند و هیچ تغییر ناگهانی یا استفاده غیرمجاز از حافظه رخ ندهد.
در پروژههای عملی، این قوانین به شما امکان میدهند بهصورت امن توابعی بنویسید که دادههای بزرگ را ویرایش کنند بدون آنکه نگران از دست رفتن Ownership یا ایجاد خطاهای حافظه باشید. سیستم Borrowing Rust بهصورت کامپایلری بررسی میشود و در صورت رعایت نکردن قوانین، خطا ایجاد میکند، بنابراین بسیاری از باگهای رایج زمان اجرا در Rust حتی ایجاد نمیشوند.
let mut s = String::from("Hello");
change_string(&mut s);
fn change_string(s: &mut String) {
s.push_str(", World");
}در این مثال، mutable Reference اجازه تغییر مقدار s را به تابع میدهد بدون آنکه Ownership منتقل شود.
ترکیب Borrowing و Ownership در پروژهها
در پروژههای واقعی، ترکیب Borrowing و Ownership باعث میشود بتوان دادهها را به شکل امن و کارآمد بین بخشهای مختلف برنامه جابجا کرد. با استفاده از immutable References میتوان چندین تابع را همزمان روی دادهها اجرا کرد بدون آنکه نگرانی از تغییر ناخواسته وجود داشته باشد. Mutable References نیز کنترل کاملی روی ویرایش دادهها فراهم میکنند و قوانین Rust تضمین میکنند که هیچ دادهای در حال استفاده آزاد یا همزمان دستکاری نمیشود.
این مکانیزمها Rust را برای توسعه سیستمهای پیچیده و حساس، نرمافزارهای چندنخی و پروژههای بزرگ تیمی ایدهآل میکند. توسعهدهنده با درک درست Borrowing و References میتواند بدون نگرانی از خطاهای حافظه، برنامههایی بهینه، ایمن و قابل نگهداری بنویسد و از تمام قابلیتهای Rust در مدیریت Ownership بهره ببرد.
جمعبندی روز سیزدهم آموزش Rust
در روز سیزدهم با Borrowing و References در Rust آشنا شدیم و دیدیم چگونه میتوان بدون انتقال Ownership به دادهها دسترسی داشت و قوانین ایمنی حافظه را رعایت کرد. تفاوت بین immutable و mutable References، قوانین Rust برای جلوگیری از همزمانی غیرمجاز و نحوه استفاده از Borrowing در توابع و پروژههای عملی بررسی شد. تسلط بر این مفاهیم، پایهای ضروری برای درک Lifetimeها، مدیریت حافظه پیشرفته و نوشتن کدهای حرفهای و امن در Rust است. در روز بعدی وارد مبحث Lifetimeها میشویم که مکمل Borrowing و References هستند و درک آنها برای پروژههای پیچیده Rust ضروری است.