
روز ۷: شرطها در Rust (if، else و match)
یکی از مهمترین بخشهای هر زبان برنامه نویسی، ساختارهای شرطی و کنترل جریان است. بدون شرطها، عملاً برنامهها نمیتوانند تصمیمگیری کنند و منطق پیچیدهای را پیادهسازی کنند. در روز هفتم از سری آموزش «Rust در ۵۰ روز» با شرطها در Rust آشنا میشویم و یاد میگیریم چگونه با استفاده از if، else و match رفتار برنامه را بر اساس شرایط مختلف کنترل کنیم. Rust در این بخش نیز فلسفه همیشگی خود یعنی شفافیت، ایمنی و قابل پیشبینی بودن را بهخوبی پیادهسازی کرده است.
برخلاف برخی زبانها که ساختارهای شرطی آنها انعطاف بیش از حد دارند و گاهی باعث رفتارهای مبهم میشوند، Rust در استفاده از شرطها بسیار سختگیر و دقیق است. شرطها در Rust باید حتماً به یک مقدار bool منتهی شوند و هیچ تبدیل ضمنی از اعداد یا انواع دیگر به true و false وجود ندارد. همین موضوع باعث میشود منطق برنامه کاملاً واضح باشد و بسیاری از خطاهای رایج قبل از اجرا شناسایی شوند.
استفاده از if در Rust
ساختار if در Rust برای بررسی یک شرط و اجرای بخشی از کد در صورت درست بودن آن استفاده میشود. شرط داخل if باید حتماً یک مقدار بولی باشد و Rust اجازه نمیدهد مقادیر عددی یا رشتهای بهصورت ضمنی به bool تبدیل شوند. این ویژگی باعث میشود شرطها بسیار خوانا و بدون ابهام باشند و رفتار برنامه همیشه مطابق انتظار توسعهدهنده باقی بماند.
بدنه if داخل بلاک آکولاد قرار میگیرد و میتواند شامل چندین دستور باشد. Rust بهجای استفاده از پرانتز اجباری برای شرط، فقط به بلاک آکولاد متکی است که این موضوع شباهت زیادی به زبانهایی مثل Go دارد. این سادگی در ظاهر، در کنار سختگیری در نوع دادهها، باعث میشود کدهای شرطی در Rust بسیار تمیز و قابل فهم باشند.
let number = 10;
if number > 5 {
println!("Number is greater than 5");
}در این مثال، شرط بهوضوح مشخص است و فقط در صورتی که مقدار number بزرگتر از ۵ باشد، کد داخل بلاک اجرا میشود.
استفاده از else و else if در Rust
در Rust میتوانید از else برای تعریف مسیر جایگزین استفاده کنید، یعنی حالتی که شرط if برقرار نباشد. همچنین با else if میتوان چند شرط مختلف را بهصورت زنجیرهای بررسی کرد. این ساختار دقیقاً مشابه بسیاری از زبانهای دیگر است، اما همچنان قوانین سختگیرانه Rust درباره نوع شرطها پابرجاست.
هر شاخه از if، else if و else یک بلاک مستقل دارد و این بلاکها میتوانند شامل هر تعداد دستور باشند. نکته مهم این است که Rust اجازه نمیدهد شاخهای بدون بلاک تعریف شود، که این موضوع از بروز خطاهای منطقی و اشتباهات رایج جلوگیری میکند. این ساختار باعث میشود منطق شرطی برنامه کاملاً شفاف و قابل دنبال کردن باشد.
let score = 75;
if score >= 90 {
println!("Excellent");
} else if score >= 60 {
println!("Passed");
} else {
println!("Failed");
}این مثال نشان میدهد چگونه میتوان چند حالت مختلف را بهصورت خوانا و منظم بررسی کرد.
if بهعنوان expression در Rust
یکی از تفاوتهای مهم Rust با بسیاری از زبانها این است که if یک expression محسوب میشود، نه صرفاً یک statement. این یعنی if میتواند مقدار بازگرداند و از آن در انتساب متغیرها استفاده شود. این ویژگی باعث میشود کدها کوتاهتر، تمیزتر و کاربردیتر باشند، بدون اینکه خوانایی کاهش پیدا کند.
البته تمام شاخههای if باید نوع یکسانی بازگردانند، در غیر این صورت کامپایلر Rust خطا میدهد. این محدودیت باعث میشود رفتار برنامه کاملاً مشخص باشد و از بروز ناسازگاریهای منطقی جلوگیری شود. استفاده از if بهعنوان expression یکی از ویژگیهایی است که در ابتدا کمی متفاوت به نظر میرسد، اما بهمرور به یکی از ابزارهای قدرتمند Rust تبدیل میشود.
let result = if number > 0 { "positive" } else { "negative" };در این مثال، مقدار متغیر result بر اساس شرط تعیین میشود، بدون نیاز به تعریف چندین متغیر یا بلاک اضافی.
match در Rust چیست و چرا مهم است؟
match یکی از قدرتمندترین ابزارهای کنترل جریان در Rust است و نقش بسیار مهمی در نوشتن کدهای ایمن و بدون خطا دارد. match برای بررسی یک مقدار در برابر چند الگو مختلف استفاده میشود و Rust اطمینان حاصل میکند که تمام حالتهای ممکن پوشش داده شدهاند. این ویژگی باعث میشود بسیاری از خطاهای منطقی که در زبانهای دیگر بهراحتی رخ میدهند، در Rust اصلاً اتفاق نیفتند.
match شباهتهایی به switch در زبانهای دیگر دارد، اما بسیار قدرتمندتر و دقیقتر است. در Rust هر شاخه match باید به یک مقدار مشخص منتهی شود و نوع این مقادیر باید یکسان باشد. این ساختار توسعهدهنده را مجبور میکند تمام سناریوهای ممکن را در نظر بگیرد و هیچ حالت مبهمی باقی نگذارد.
مثال ساده از match در Rust
در یک match، مقدار مورد نظر با الگوهای مختلف مقایسه میشود و در صورت تطابق، کد مربوط به آن شاخه اجرا میشود. Rust از بالا به پایین الگوها را بررسی میکند و اولین تطابق را اجرا میکند. وجود شاخه _ بهعنوان حالت پیشفرض الزامی است، مگر اینکه تمام حالتها بهصورت صریح پوشش داده شده باشند.
این رویکرد باعث میشود match ابزاری بسیار مناسب برای کار با enumها، مقادیر عددی محدود و حالتهای مختلف منطقی باشد. بسیاری از کدهای حرفهای Rust بهشدت به match متکی هستند، چون هم خوانایی بالایی دارد و هم ایمنی کد را تضمین میکند.
let day = 3;
match day {
1 => println!("Saturday"),
2 => println!("Sunday"),
3 => println!("Monday"),
_ => println!("Other day"),
}تفاوت if و match در Rust
if بیشتر برای بررسی شرطهای ساده و منطقی استفاده میشود، در حالی که match برای بررسی چندین حالت مشخص و از پیش تعریفشده مناسبتر است. وقتی تعداد شرطها زیاد میشود یا با enumها سر و کار دارید، match معمولاً انتخاب بهتری نسبت به ifهای تو در تو است. این موضوع باعث میشود کدها خواناتر و قابل نگهداریتر باشند.
Rust شما را مجبور نمیکند همیشه از match استفاده کنید، اما طراحی زبان بهگونهای است که در بسیاری از سناریوها match طبیعیترین و امنترین گزینه است. انتخاب درست بین if و match یکی از مهارتهایی است که با تمرین و تجربه در Rust بهدست میآید.
جمعبندی روز هفتم آموزش Rust
در روز هفتم با ساختارهای شرطی Rust شامل if، else و match آشنا شدیم و یاد گرفتیم چگونه منطق تصمیمگیری را بهصورت ایمن و شفاف پیادهسازی کنیم. Rust با سختگیری در نوع شرطها و پوشش کامل حالتها، کمک میکند کدهایی بنویسیم که هم خوانا باشند و هم احتمال خطا در آنها به حداقل برسد. درک درست این مفاهیم نقش مهمی در نوشتن کدهای حرفهای Rust دارد.
در روز بعدی وارد مبحث حلقهها در Rust میشویم و با loop، while و for آشنا خواهیم شد. از این نقطه به بعد، ابزارهای اصلی کنترل جریان Rust کاملتر میشوند.