برای طرح سوال و دسترسی به آموزش ها  کانال ما در تلگرام بپویندید  

قانون‌های طلایی rust در تصمیم‌گیری انتخاب موارد پیچیده

یکی از چیزایی که زبان rust از سایر زبان‌ها متمایز می‌کنه ویژگی های خاص این زبان برنامه‌نویسی به ویژه بحث مالکیت و سخت‌گیری های مدیریت حافظه در rust ممکنه آزاردهنده باشه، با توجه به مطالعات و تجربیاتم در زمینه rust به این مطلب رو می‌نویسم که تا ببینیم چطور میشه از این‌ها استفاده کرد. و انتخاب های پیچیده رو در قالب یک طرح مفهومی پیاده کنیم. قانون طلایی هر چیزی رو با چاشنی نظر بیان می‌کنیم.

سعی می‌کنم مطلب رو از ساده به پیچیده تر طرح کنم:

انتخاب همیشه بین String, &str در rust

این انتخاب معمولا در پارامتر های ورودی توابع و ساختار struc استفاده مطرح میشه، قانون طلایی استفاده چیه؟

اگر سوال بالا رو نتونستم جواب بدم چه کار کنم؟ &str بذار اگر گیر کردی پس مجبوری String بذاری.

یه سوال مهم دیگه: اگر همیشه string استفاده کنم چی میشه؟ از نظر عملکرد برنامه، همیشه فاجعه رخ نمی‌ده اما هزینه برنامه بالا میره، در واقع اون موقع شما فلسفه راست رو رعایت نکردید، و کدتون از حالت idiomatic خارج میشه. پس جایی هزینه انتقال رو پرداخت می‌کنیم که لازمه. به عبارتی میشه گفت: در Rust معمولاً تا وقتی فقط نیاز به خواندن متن داریم از &str استفاده می‌کنیم و فقط زمانی سراغ Strting میریم که واقعاً به مالکیت داده یا تغییر محتوا نیاز داشته باشیم

 

در زبان rust چه زمانی clone لازم میشه

قانون طلایی:

.clone() بزنی.

خب روش انتخاب:

  1. اگر می‌خواهم بخونم: &str یا &T
  2. اگر می‌خواهم مالکیت رو منتقل کنم به یه صاحب جدید داده و خودم بی خیالش بشم:‌ move
  3. .clone()

 

قانون طلایی انتخاب بین حلقه یا iterator در rust

متن ساده:

  1. for ساده استفاده کن
  2. collect و …)
  3. کد کوتاه‌تر، ایمن‌تر و 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 باید استفاده بشه

حرف حسابشون چیه:

  1. بردار
  2. عوض کن
  3. بگذار سرجاش

تمام

مشکل هشتم: 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> چیه؟😉

 


انتشار

در

,

توسط

برچسب‌ها:

نظرات

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *