
روز ۴: متغیرها در Rust و تفاوت immutable و mutable
یکی از اولین مفاهیمی که هنگام یادگیری زبان Rust با آن روبهرو میشوید، نحوه تعریف و استفاده از متغیرهاست. Rust برخلاف بسیاری از زبانهای برنامه نویسی، بهصورت پیشفرض متغیرها را immutable یا غیرقابل تغییر در نظر میگیرد. این تصمیم طراحی در نگاه اول ممکن است عجیب یا حتی محدودکننده به نظر برسد، اما در عمل یکی از مهمترین دلایل ایمنی بالا و پایداری کدهای Rust است. در روز چهارم از سری آموزش «Rust در ۵۰ روز» بهصورت عمیق و مفهومی بررسی میکنیم متغیرها در Rust چگونه کار میکنند و چرا تفاوت بین immutable و mutable تا این حد مهم است.
در زبانهایی مثل Python یا JavaScript، تغییر مقدار متغیرها کاملاً عادی و رایج است و معمولاً محدودیتی برای این کار وجود ندارد. اما Rust مسیر متفاوتی را انتخاب کرده و توسعهدهنده را مجبور میکند آگاهانه درباره تغییرپذیری دادهها تصمیم بگیرد. این رویکرد باعث میشود بسیاری از باگها و خطاهای منطقی، قبل از اجرا و در زمان کامپایل شناسایی شوند. در این مقاله یاد میگیریم چگونه متغیرها را تعریف کنیم، چه زمانی immutable یا mutable بودن منطقی است و این تصمیم چه تأثیری روی کیفیت کد دارد.
تعریف متغیر در Rust
برای تعریف متغیر در Rust از کلمه کلیدی let استفاده میشود. بهصورت پیشفرض، هر متغیری که با let تعریف میشود immutable است و بعد از مقداردهی اولیه، امکان تغییر مقدار آن وجود ندارد. این رفتار پیشفرض باعث میشود توسعهدهنده از همان ابتدا نسبت به تغییرات دادهها حساس باشد و بدون فکر متغیرها را تغییر ندهد. این موضوع بهخصوص در پروژههای بزرگ و چندنفره اهمیت بسیار زیادی دارد.
Rust همچنین دارای سیستم قدرتمند type inference است، به این معنا که در بسیاری از مواقع نیازی به مشخص کردن نوع متغیر نیست و کامپایلر بهصورت خودکار نوع داده را تشخیص میدهد. این ویژگی باعث میشود کدها هم خواناتر باشند و هم از نظر ایمنی تایپی در سطح بالایی قرار بگیرند. ترکیب immutable بودن پیشفرض و type inference یکی از تفاوتهای مهم Rust با بسیاری از زبانهای دیگر است.
let x = 10;
در این مثال، متغیر x مقدار 10 را دریافت کرده و از این لحظه به بعد قابل تغییر نیست. اگر تلاش کنید مقدار جدیدی به آن اختصاص دهید، کامپایلر Rust خطا خواهد داد و اجازه اجرای برنامه را نمیدهد.
مفهوم immutable در Rust
immutable بودن متغیرها به این معناست که بعد از مقداردهی اولیه، مقدار آنها ثابت باقی میماند. این مفهوم نقش بسیار مهمی در جلوگیری از خطاهای ناخواسته دارد، مخصوصاً در شرایطی که چند بخش مختلف از برنامه به یک داده دسترسی دارند. وقتی متغیری immutable است، میتوانید با اطمینان کامل بدانید که مقدار آن در طول اجرای برنامه تغییر نخواهد کرد.
Rust با اجبار توسعهدهنده به استفاده آگاهانه از متغیرهای mutable، ذهنیت متفاوتی نسبت به مدیریت دادهها ایجاد میکند. این موضوع باعث میشود کدها قابل پیشبینیتر باشند و خواندن آنها برای دیگران یا حتی خودتان در آینده سادهتر شود. بسیاری از باگهایی که در زبانهای دیگر به دلیل تغییر ناخواسته دادهها ایجاد میشوند، در Rust اساساً امکان وقوع ندارند.
متغیرهای mutable و کلمه کلیدی mut
در Rust اگر بخواهید مقدار یک متغیر را تغییر دهید، باید بهصورت صریح آن را mutable تعریف کنید. این کار با اضافه کردن کلمه کلیدی mut هنگام تعریف متغیر انجام میشود. این تصمیم آگاهانه باعث میشود هر تغییر در دادهها کاملاً مشخص و قابل ردیابی باشد و توسعهدهنده دقیقاً بداند کدام بخشهای کد امکان تغییر دارند.
استفاده از mut به این معنا نیست که Rust شما را محدود میکند، بلکه هدف آن افزایش شفافیت و کاهش خطاست. وقتی در کدی mut میبینید، فوراً متوجه میشوید که این متغیر در طول اجرا تغییر خواهد کرد. این موضوع در پروژههای بزرگ کمک زیادی به درک سریعتر کد و دیباگ کردن آن میکند.
let mut counter = 0; counter = 1;
در این مثال، متغیر counter بهصورت mutable تعریف شده و تغییر مقدار آن کاملاً مجاز است. اگر کلمه mut وجود نداشت، کامپایلر Rust اجازه این تغییر را نمیداد.
چرا Rust متغیرها را پیشفرض immutable قرار داده است؟
یکی از اهداف اصلی Rust افزایش ایمنی و کاهش باگهای زمان اجراست. بسیاری از خطاهای رایج در نرمافزارها به دلیل تغییرات ناخواسته در دادهها ایجاد میشوند. با immutable بودن پیشفرض متغیرها، Rust این دسته از خطاها را بهشدت کاهش میدهد و توسعهدهنده را مجبور میکند فقط در صورت نیاز واقعی از mutable استفاده کند.
این رویکرد بهخصوص در برنامههای concurrent و چندریسمانی اهمیت پیدا میکند. وقتی دادهها تغییرناپذیر باشند، احتمال بروز race condition به حداقل میرسد. به همین دلیل Rust توانسته همزمانی امن را بدون استفاده از Garbage Collector فراهم کند و این یکی از بزرگترین مزیتهای این زبان محسوب میشود.
تفاوت mut با shadowing در Rust
Rust علاوه بر mut مفهومی به نام shadowing دارد که گاهی باعث سردرگمی برنامهنویسان تازهکار میشود. در shadowing شما میتوانید یک متغیر جدید با همان نام متغیر قبلی تعریف کنید و مقدار یا حتی نوع آن را تغییر دهید. این کار با let انجام میشود و نیازی به mut ندارد.
Shadowing با mutable بودن تفاوت اساسی دارد، چون در واقع متغیر جدیدی ایجاد میشود نه اینکه مقدار متغیر قبلی تغییر کند. این ویژگی در شرایطی که میخواهید داده را مرحلهبهمرحله پردازش کنید بسیار مفید است و همچنان مزایای immutable بودن را حفظ میکند. درک تفاوت بین mut و shadowing نقش مهمی در نوشتن کدهای تمیز و حرفهای در Rust دارد.
بهترین زمان استفاده از immutable و mutable
در Rust توصیه میشود تا حد امکان از متغیرهای immutable استفاده کنید و فقط زمانی سراغ mutable بروید که واقعاً نیاز به تغییر مقدار وجود دارد. این رویکرد باعث میشود کدها امنتر، خواناتر و قابل نگهداریتر باشند. immutable بودن بهخصوص برای مقادیر ثابت، تنظیمات و دادههایی که نباید تغییر کنند، انتخاب ایدهآلی است.
در مقابل، متغیرهای mutable برای شمارندهها، bufferها و ساختارهایی که بهصورت طبیعی تغییر میکنند کاربرد دارند. Rust شما را مجبور نمیکند همیشه immutable باشید، بلکه شما را وادار میکند آگاهانه تصمیم بگیرید. همین آگاهی تفاوت یک کد معمولی با یک کد حرفهای در Rust را رقم میزند.
جمعبندی روز چهارم آموزش Rust
در روز چهارم یاد گرفتیم متغیرها در Rust چگونه تعریف میشوند و چرا immutable بودن پیشفرض یکی از مهمترین ویژگیهای این زبان است. همچنین تفاوت بین immutable و mutable، کاربرد کلمه کلیدی mut و فلسفه پشت این طراحی را بررسی کردیم. این مفاهیم پایهای هستند اما در تمام بخشهای Rust نقش کلیدی دارند و درک درست آنها برای ادامه مسیر یادگیری ضروری است.
در روز بعدی وارد دنیای انواع دادهها در Rust میشویم و با type system قدرتمند این زبان بیشتر آشنا خواهیم شد. از اینجا به بعد، کمکم تصویر کاملتری از منطق Rust در ذهن شما شکل میگیرد.