عبارات شرطی
عبارات شرطی به شما امکان میدهند بلوکهای مختلف کد را بسته به اینکه یک شرط true یا false ارزیابی شود، اجرا کنید. شرایط باید به یک مقدار bool ارزیابی شوند.
if (condition) {
// executes if condition is true
} else {
// executes if condition is false
}
شرطهای زنجیرهای:
var grade: char;
if (score >= 90) {
grade = 'A';
} else if (score >= 75) {
grade = 'B';
} else {
grade = 'C';
}
ساختارهای حلقه
یک حلقه for امکان تکرار یک بلوک کد را چندین بار فراهم میکند. معمولاً از سه بخش اختیاری درون سرآیند حلقه تشکیل شده است:
- مقداردهنده اولیه (Initializer) - یک بار قبل از شروع حلقه اجرا میشود (اغلب برای اعلان و مقداردهی یک شمارنده استفاده میشود).
- شرط (Condition) - قبل از هر تکرار بررسی میشود؛ اگر false باشد، حلقه خارج میشود.
- افزایش/بهروزرسانی (Increment/Update) - پس از هر تکرار اجرا میشود.
for (initializer; condition; increment) {
// body
}
حلقه شمارنده کلاسیک
for (var i = 0; i < 10; i++) {
printf("%d\n", i);
}
با i که مقادیر 0 تا 9 را میگیرد اجرا میشود.
حلقه با افزایش دستی
for (var i = 0; i < 10;) {
// executes while i < 10
// you should manually increment i inside the body
i++;
}
در اینجا، بخش افزایش حذف شده است. حلقه تا زمانی که شرط false شود ادامه مییابد، اما شما کنترل میکنید که i چه زمانی بهروز شود.
حلقه بدون شرط با مقداردهنده اولیه
for (var attempts = 0;) {
if (attempts > 5) {
break;
}
try_connect();
attempts++;
}
با عدم ارائه شرط، حلقه بینهایت است مگر اینکه با break یا return خارج شود.
حلقه بینهایت خالص
Warning!
An infinite loop can also be written as:
while (true) {
handle_event();
}
Both forms are semantically equivalent. However, using for { ... } is preferred for infinite loops to keep the codebase stylistically consistent and to avoid mixing multiple looping styles for the same concept.
for {
// infinite loop with no initializer, no condition, no increment
// must be exited with break or return
}
این فرم هیچ مقداردهنده اولیه، شرط و بهروزرسانی ندارد. باید به صورت صریح خاتمه یابد.
دستور while
یک حلقه while یک بلوک کد را تا زمانی که یک شرط true ارزیابی شود، به طور مکرر اجرا میکند. شرط قبل از هر تکرار بررسی میشود. اگر شرط در ابتدا false باشد، بدنه حلقه هرگز اجرا نمیشود.
while (is_running) {
tick();
}
var attempts = 0;
while (true) {
printf("attempt %d\n", attempts);
attempts++;
if (attempts >= max_retries) {
break;
}
}
دستور Switch
Info
This is not pattern matching. Cases in Cyrus are always compared against raw values, not structural patterns or conditions.
دستور switch جریان کنترل ساختاریافتهای را بر اساس مقدار یک عبارت فراهم میکند. از انواع enum با تخریبسازی (destructuring)، تطبیق مبتنی بر مقدار و یک شاخه default اختیاری پشتیبانی میکند.
فرم کلی به صورت زیر است:
فرم پایه
switch (expression) {
case pattern => {
// body
}
default => {
// optional fallback
}
}
هر case با استفاده از => معرفی میشود و بلوک مرتبط خود را زمانی که الگو مطابقت دارد اجرا میکند.
اجرا به case بعدی سرایت نمیکند (fall through)؛ دقیقاً یک شاخه مطابق اجرا میشود.
Switch روی Enumها
هنگام switch روی مقادیر enum، هر case یک variant خاص را مطابقت میدهد.
Variantهای بدون payload با نام مطابقت میکنند، در حالی که variantهای دارای داده مرتبط میتوانند فیلدهای خود را مستقیماً تخریب (destructure) کنند.
enum Color {
Red,
Green = "green!",
Custom(uint, uint, uint)
}
pub fn main() {
const color = Color.Green;
switch (color) {
case .Red => {
printf("red\n");
}
case .Green(value) => {
printf("%s\n", value);
}
case .Custom(r, g, b) => {
printf("(%d, %d, %d)\n", r, g, b);
}
}
}
switch جامع (exhaustive) است: همه variantهای ممکن Color پوشش داده شدهاند.
Switch روی Enum بدون Payload
enum Color {
Red,
Purple,
Black
}
pub fn main() {
const color = Color.Black;
switch (color) {
case .Red => {
printf("red\n");
}
case .Purple => {
printf("purple\n");
}
case .Black => {
printf("black\n");
}
}
}
هر case یک variant مشخص از enum را مطابقت میدهد. از آنجا که همه variantها پوشش داده شدهاند، نیازی به شاخه default نیست.
تخریبسازی مقادیر برچسبدار
انواع enum معمولاً به عنوان اتحاد برچسبدار (tagged unions) استفاده میشوند. دستور switch امکان استخراج ایمن مقدار ذخیرهشده بر اساس variant فعال را فراهم میکند.
enum Value {
Int(int64),
Text(char*)
}
pub fn main() {
const value = Value.Text("Cyrus!");
switch (value) {
case .Int(number) => {
printf("int_value(%d)\n", number);
}
case .Text(text) => {
printf("text_value(%s)\n", text);
}
}
}
در اینجا، متغیر مقید (number, text) فقط درون بلوک case مربوطه خود قابل دسترسی است.
تطبیق چندین Variant از Enum
وقتی یک variant از enum فاقد payload است، میتوان آن را با سایر variantهای بدون payload با استفاده از عملگر | درون یک case ترکیب کرد.
این امکان گروهبندی چندین variant را تحت یک شاخه فراهم میکند.
enum Color {
Red,
Green,
Custom(uint, uint, uint)
}
pub fn main() {
const color = Color.Green;
switch (color) {
case .Red | .Custom => {
printf("primary\n");
}
case .Green => {
printf("green\n");
}
}
}
فقط variantهای بدون payload ممکن است با | گروهبندی شوند. Variantهای دارای payload باید به صورت جداگانه مطابقت داده شوند تا فیلدهایشان قابل تخریب باشد. Caseهای گروهبندی شده به عنوان یک شاخه واحد رفتار میکنند؛ هیچ binding الگویی مجاز نیست.
Switch روی مقادیر غیر Enum
Switch همچنین میتواند با عبارات غیر enum مانند اعداد صحیح، رشتهها یا سایر مقادیر قابل مقایسه استفاده شود.
const text = "Cyrus!";
switch (text) {
case "Cyrus!" => {
printf("Cyrus The Great\n");
}
default => {
printf("unknown\n");
}
}
در این فرم:
- هر case عبارت switch را با یک مقدار مشخص مقایسه میکند
- Default زمانی اجرا میشود که هیچ case مطابقت نداشته باشد
- تطبیق مبتنی بر مقدار است، نه مبتنی بر الگو
بلوکهای پرش
کوروش از بلوکهای پرش با استفاده از دستور goto پشتیبانی میکند. بلوکهای پرش به شما امکان میدهند کنترل را به یک نقطه برچسبگذاری شده در تابع جاری منتقل کنید. اگرچه goto باید به ندرت استفاده شود، میتواند جریانهای کنترل سطح پایین یا منطق شبیه به ماشین حالت را ساده کند.
یک برچسب (label) یک شناسه است که با دو نقطه دنبال میشود و دستور goto اجرا را به آن برچسب منتقل میکند:
pub fn main() {
label_name:
// code
goto label_name; // jumps to the labeled block
}
برچسبها باید درون همان تابع تعریف شوند.
import std::libc{printf, exit};
pub fn main() {
var x = 0;
increment: // label for incrementing
x++;
check: // label for condition check
if (x < 5) {
goto increment; // jump back to increment
} else {
printf("%d\n", x);
exit(0);
}
}

