یکی از چیزایی که زبان rust از سایر زبانها متمایز میکنه ویژگی های خاص این زبان برنامهنویسی به ویژه بحث مالکیت و سختگیری های مدیریت حافظه در rust ممکنه آزاردهنده باشه، با توجه به مطالعات و تجربیاتم در زمینه rust به این مطلب رو مینویسم که تا ببینیم چطور میشه از اینها استفاده کرد. و انتخاب های پیچیده رو در قالب یک طرح مفهومی پیاده کنیم. قانون طلایی هر چیزی رو با چاشنی نظر بیان میکنیم.
سعی میکنم مطلب رو از ساده به پیچیده تر طرح کنم:
انتخاب همیشه بین String, &str در rust
این انتخاب معمولا در پارامتر های ورودی توابع و ساختار struc استفاده مطرح میشه، قانون طلایی استفاده چیه؟
اگر سوال بالا رو نتونستم جواب بدم چه کار کنم؟ &str بذار اگر گیر کردی پس مجبوری String بذاری.
یه سوال مهم دیگه: اگر همیشه string استفاده کنم چی میشه؟ از نظر عملکرد برنامه، همیشه فاجعه رخ نمیده اما هزینه برنامه بالا میره، در واقع اون موقع شما فلسفه راست رو رعایت نکردید، و کدتون از حالت idiomatic خارج میشه. پس جایی هزینه انتقال رو پرداخت میکنیم که لازمه. به عبارتی میشه گفت: در Rust معمولاً تا وقتی فقط نیاز به خواندن متن داریم از &str استفاده میکنیم و فقط زمانی سراغ Strting میریم که واقعاً به مالکیت داده یا تغییر محتوا نیاز داشته باشیم
در زبان rust چه زمانی clone لازم میشه
قانون طلایی:
.clone() بزنی.
خب روش انتخاب:
- اگر میخواهم بخونم: &str یا &T
- اگر میخواهم مالکیت رو منتقل کنم به یه صاحب جدید داده و خودم بی خیالش بشم: move
- .clone()
قانون طلایی انتخاب بین حلقه یا iterator در rust
متن ساده:
- for ساده استفاده کن
- collect و …)
- کد کوتاهتر، ایمنتر و idiomatic تولید میکنن و میشه باهاشون lazy evaluation داشت، ولی بعضی وقتها حلقه ساده خواناتر است
یه سوال مهم دیگه: اگر واقعا نمیدونستی کدوم رو انتخاب کنی؟ اون موقع for رو استفاده کن
قانون طلایی طول عمر یا لایف تایم در rust
اولش بگم آخ بسوزه پدر لایف تایم که لایف تایم عمر منو گرفت اون زمان 😁
- &T) نباید بعد از دادهای که بهش اشاره میکنه استفاده شود.
- داده صاحب اصلی (owner) باید تا آخرین استفاده از reference زنده باشد.
- اگر میخوای reference رو برگردانی از یک تابع، باید lifetime ورودی رو به خروجی گره بزنی یا داده رو منتقل کنی (move) یا clone کنی.
یه سوال مهم دیگه: اگر واقعا نمیدونستی کی باید لایف تایم بنویسی ننویس کامپایل خودش بهت گیر میده ولی وقتی بهت گیر داده میگه:'static بذار که معمولا این انتخاب درست نیست چون معمولا به این معنی طول عمر این برابر با کل برنامه هست.
where در امضای تابع در زبان راست
به صورت کلی where مینویسیم تا کد خواناتر شود.
fn print<T: Display>(value: T){
fn print<T>(value: T)
where
T: Display,
{
این دو تا کی هستند و تفاوتی ندارند.
رسیدیم به قسمت سخت ماجرا اشاره گر های هوشمند تغییر داده و فانتوم data وبقیه ماجرا ها که گیر اصلی معمولا تو ایناست با طرح مشکل قانون طلایی رو مطرح میکنیم:
قانون طلایی استفاده از اشاره گرهای هوشمند و برنامه نویس همزمان در Rust
مقدمه لایه صفر: Rust ایدهآل
میشه گفت Rust دوست داره همه چیز این شکلی باشد، یک مالک بیشتر نداشته باشه بقیه غلط بکنن فضولی بکنند تو کار داده 😁
همه چیز خوشحال است.
مشکل اول: چند نفر میخواهند مالک باشند
که این اتفاق معمولا در برنامههای gui زیاد میوفته:
هر دو نیاز دارند زنده نگهش دارن، اینجا:Rc<T>میاد. جفتک میندازه 😂
سوال: آیا Rc اجازه mutation یا تغییر میده؟
عمرااااااااا
چون چند مالک وجود دارد.
Rust نمیتواند بفهمد کدام یکی الان دارد مینویسد
مشکل دوم: چند مالک + نیاز به تغییرات
اینجا: Rc<RefCell<T>>متولد میشه تا به شما دسترسی بیشتری بدهد. حرف حسابشون چیه:
Rc میگه:
مالکهای متعدد
RefCell میگه:
borrow checker رو بفرست runtime به گیر نده سرجدت 😂
مشکل سوم: گراف داری و memory leak میگیری
به عبارت ساده تر یعنی تو در تو دارن مقادیر به صورت پدر و فرزند همه دیگرو صاحب میشن، اصن کار RC اینه که ببینه کی باید اینو تو حافظه از بین ببره واسه همین تعداد مصرف کننده رو میشماره اینجا چه به دنیا میادش: Weak
حرف حسابش چیه:
من صاحب (بچه😂) نیستم فقط آدرس رو میشناسم ( کارت تموم شد میام در خونتون😂 حافظه رو پس میگیرم)
مشکل چهارم: Multi Thread
اینجا دیگه RC به چوخ میره و میمیره 😂
جایگزین چه کوفتیه:
Arc<T>
اتمیک هستش بمب اتم نیست ولی همه جا یعنی بین تمام ریسمان ها Thread تعداد استفاده رو میشماره تا حافظه رو پس بگیره
این مشکل خیلی باحاله:
مشکل پنجم: Arc دارم ولی mutation میخواهم
اینجا: Arc<Mutex<T>>ظهور پیدا میکنه از اعماق غارهای تو در توی rust
Arc حرف حسابش چیه؟
مالکهای متعدد اونم از نوع اتمی که همه جا فضولی میکنه
Mutex چیه:
فقط یک writer وجود داره بقیه دسته خر باید تماشا کنن تا کار سکس اون نویسنده با داده تموم بشه😐😂
مشکل ششم: خواندن زیاد است
یعنی تعداد فوضلایی که به داده دسترسی دارن و مدام میخونن ببین چی توشه، در بین ریسمان ها زیاد هست مثلا ۱۰۰ خواننده داده اینجا Mutex میشه مثل صف نونوایی و RwLock<T> میشه مثل استدیوم همه دارن میبینن بازی کن با توپ چیکار میکنه ولی یه نفر فقط توپ دستشه و داره تغییرات ایجاد میکنه 😉
مشکل هفتم: فقط &self دارم
یعنی mute &self نمیتونم داشته باشم اینجا cell یا refcell به کار میاد که از cell استفاده میکنم وقتی که داده ام حجمش مشخص هستش مثل اعداد و bool و … وقتی سنگین میشه مثل struct یا string اون موقع refcell باید استفاده بشه
حرف حسابشون چیه:
- بردار
- عوض کن
- بگذار سرجاش
تمام
مشکل هشتم: type وجود دارد ولی فیلد وجود ندارد
این واقعا یکی از شاهکار های عجیب rust هست شاید عجیب ترین قسمت که فانتوم دیتا اینجا متولد نمیشه اینجا خودشو به زور جا میکنه مثالشم از AI بپرسید بهتون میگه
حرف حساب کامپایلر چیه:
مثلا: تو اصلاً T یا ‘a رو نگه نمیداری مگه من اسکول شدم که بیام ازت قبول کنم اینا رو
حرف حساب ما چیه:
من وابستهام پس اینو یه روح ( فانتوم در نظر بگیر) تو نمیفهمی من میفهمم:
کامپایلر میبیند:
_marker: PhantomData<T>
و میگوید:
حله داداش
پس این struct واقعاً به T وابسته است من شاکول بودم 😁
اگر واقعاً نمیدونستی Cell یا RefCell؟
اول RefCell.
بعد اگر دیدی فقط یک Copy type داری،
به Cell تبدیلش کن.
اگر واقعاً نمیدونستی Mutex یا RwLock؟
اول Mutex.
فقط وقتی مطمئن شدی
تعداد Readerها خیلی بیشتر از Writerهاست
برو سراغ RwLock.
خب تموم شد، شاید در طول زمان اینو بیشتر آپدیتش کنم یادم بیاد چیزی، اما یه سوال چالش برانگیز از شما می پرسم:
تفاوت Arc<Mutex> با Mutex<arc> چیه؟😉
اول از همه کوچک ترین عضو مجموعه 4xmen بنده حقیر هستم.
در ثانی یک توسعه دهنده هستم زمینه های تخصصی کارم :
Delphi, Rust ,PHP, C++ ,Python, JavaScript, Unity game engine, C#, asm
و علاقه مند به لینوکس، RCE ، کریپتوگرافی هستم.
تا الان حضرت حق اینا رو به ما داده و هر وقت که بخواد ازمون میگیره دست خودشه.
یا حق، با حق، تا حق






دیدگاهتان را بنویسید لغو پاسخ