1. مفاهیم پایه (Rust Fundamentals)
تفاوت let و let mut چیست و چرا Rust بهصورت پیشفرض immutable است؟
پاسخ بلند
در Rust، متغیرهایی که با let تعریف میشوند بهصورت پیشفرض immutable هستند و تنها با استفاده از let mut میتوان آنها را قابل تغییر کرد. این تصمیم یک انتخاب طراحی آگاهانه است که ریشه در ایمنی، پیشبینیپذیری و سهولت reasoning دارد.
immutability باعث میشود:
- state برنامه قابلردیابیتر باشد
- data raceها در زمان کامپایل حذف شوند
- کامپایلر بتواند بهینهسازیهای تهاجمیتری انجام دهد
- تغییرات ناخواستهی داده کاهش یابد
Rust توسعهدهنده را مجبور میکند که «قصد تغییر» را بهصورت صریح اعلام کند. این موضوع در سیستمهای concurrent و codebaseهای بزرگ اهمیت حیاتی دارد.
پاسخ کوتاه
let متغیر immutable تعریف میکند و let mut mutable؛ پیشفرض بودن immutability برای افزایش ایمنی، خوانایی و حذف خطاهای همزمانی در زمان کامپایل است.
مفهوم Ownership را توضیح دهید
پاسخ بلند
Ownership هستهی اصلی مدل مدیریت حافظه در Rust است. هر مقدار در Rust دقیقاً یک مالک (owner) دارد. زمانی که owner از scope خارج میشود، مقدار بهصورت خودکار آزاد میشود.
قوانین اصلی ownership:
- هر مقدار فقط یک owner دارد
- با انتقال ownership (move)، owner قبلی دیگر معتبر نیست
- وقتی owner از scope خارج شود،
dropفراخوانی میشود
این مدل امکان مدیریت حافظه بدون GC و بدون manual memory management را فراهم میکند و بسیاری از خطاهای رایج مانند use-after-free و double-free را در زمان کامپایل حذف میکند.
پاسخ کوتاه
Ownership مدلی است که در آن هر مقدار فقط یک مالک دارد و با خروج مالک از scope حافظه آزاد میشود، بدون نیاز به GC یا مدیریت دستی.
چرا Rust از Garbage Collector استفاده نمیکند؟
پاسخ بلند
Rust بهجای GC از ownership + borrowing + lifetimes استفاده میکند تا مدیریت حافظه را به زمان کامپایل منتقل کند. GC هزینههایی مانند:
- latency غیرقابل پیشبینی
- مصرف منابع اضافی
- توقفهای دورهای (stop-the-world)
را به سیستم تحمیل میکند.
Rust برای سیستمهای low-level، real-time و high-performance طراحی شده و حذف GC امکان کنترل دقیقتر بر زمان و منابع را فراهم میکند، در حالی که ایمنی حافظه حفظ میشود.
پاسخ کوتاه
چون Rust ایمنی حافظه را در زمان کامپایل تضمین میکند و GC باعث latency و overhead غیرقابل پیشبینی میشود.
تفاوت بین move و copy چیست؟ چه typeهایی Copy هستند؟
پاسخ بلند
بهصورت پیشفرض، assignment یا pass کردن یک مقدار باعث move شدن ownership میشود. بعد از move، متغیر قبلی دیگر قابل استفاده نیست.
برخی typeها رفتار Copy دارند؛ یعنی بهجای انتقال ownership، یک کپی بیتی از مقدار ساخته میشود. این typeها:
- ساده و بدون heap allocation هستند
- resource ownership ندارند
نمونه typeهای Copy:
- اعداد primitive (
i32,u64,f64) boolchar- tupleهایی که تمام اعضایشان
Copyباشند
پاسخ کوتاه
move ownership را منتقل میکند ولی copy یک کپی بیتی میسازد؛ typeهای ساده مثل اعداد و bool Copy هستند.
Borrowing و قوانین آن چیست؟ چرا همزمان چند mutable reference مجاز نیست؟
پاسخ بلند
Borrowing اجازه میدهد بدون انتقال ownership به داده دسترسی داشته باشیم. Rust دو نوع borrow دارد:
- immutable borrow (
&T) - mutable borrow (
&mut T)
قوانین borrowing:
- همزمان میتوان چند reference immutable داشت
- یا فقط یک reference mutable
- mutable و immutable همزمان مجاز نیستند
این محدودیت برای جلوگیری از data race، aliasing + mutation و رفتارهای undefined است. Rust این تضمینها را در زمان کامپایل enforce میکند.
پاسخ کوتاه
Borrowing یعنی دسترسی بدون ownership؛ فقط یک mutable reference مجاز است تا از data race و رفتار undefined جلوگیری شود.
تفاوت &T و &mut T چیست؟
پاسخ بلند
&T یک reference فقطخواندنی است و اجازهی تغییر مقدار را نمیدهد.
&mut T اجازهی خواندن و نوشتن را میدهد اما:
- باید یکتا باشد
- هیچ reference دیگری همزمان وجود نداشته باشد
این تمایز بخش مهمی از سیستم ایمنی Rust است.
پاسخ کوتاه
&T فقط خواندنی است، &mut T قابل تغییر است و باید یکتا باشد.
lifetime چیست و چه زمانی نیاز به annotation داریم؟
پاسخ بلند
Lifetime مشخص میکند یک reference تا چه مدت معتبر است. Rust معمولاً با lifetime elision آنها را بهصورت خودکار استنتاج میکند.
Annotation زمانی لازم است که:
- چند reference ورودی و خروجی وجود دارد
- رابطهی بین lifetimeها برای کامپایلر مبهم است
- در structهایی که reference نگه میدارند
Lifetimeها رفتار runtime ندارند و صرفاً ابزاری برای بررسی ایمنی در زمان کامپایل هستند.
پاسخ کوتاه
Lifetime طول اعتبار reference را مشخص میکند و فقط وقتی annotation لازم است که کامپایلر نتواند آن را استنتاج کند.
چرا Rust دارای Option و Result<T, E> است و از null استفاده نمیکند؟
پاسخ بلند
null منبع یکی از رایجترین خطاهای runtime است. Rust بهجای آن از type system استفاده میکند تا نبود مقدار یا خطا را صریح و قابل بررسی کند.
Option<T>: وجود یا عدم وجود مقدارResult<T, E>: موفقیت یا خطا با اطلاعات دقیق
این رویکرد:
- خطاها را به زمان کامپایل نزدیک میکند
- توسعهدهنده را مجبور به handle کردن حالتها میکند
- از panicها و crashهای ناگهانی جلوگیری میکند
پاسخ کوتاه
چون Option و Result خطا و نبود مقدار را صریح و type-safe میکنند و مشکلات کلاسیک null را حذف میکنند.