متغیرهای سراسری

    متغیرهای سراسری در سطح بالاترین scope اعلان می‌شوند. آنها بسته به اصلاح‌کننده دید خود، در سراسر ماژول یا بسته قابل دسترسی هستند.

    دید (Visibility)

    • خصوصی (Private): بدون اصلاح‌کننده اعلان می‌شود؛ فقط درون ماژول جاری قابل دسترسی است.
    • عمومی (pub): از سایر ماژول‌ها یا فایل‌ها قابل دسترسی است.
    const VERSION = "1.0"; // خصوصی، تغییرناپذیر
    
    pub const COUNTER = 0; // عمومی، تغییرناپذیر
    

    تغییرپذیری (Mutability)

    • const: پس از اعلان تغییرناپذیر است. تلاش برای تخصیص مجدد باعث خطای کامپایل می‌شود.
    • var: تغییرپذیر است؛ مقدار می‌تواند در طول چرخه حیات برنامه تغییر کند.
    const PI = 3.14159;
    
    PI = 3.14; // خطا!
    

    نمادهای خارجی (External Symbols)

    از کلیدواژه extern برای اعلان نمادهایی که در کتابخانه‌های خارجی یا واحدهای ترجمه دیگر تعریف شده‌اند استفاده کنید. این اعلان‌ها شامل مقداردهنده اولیه نیستند.

    extern errno: int32; // نماد خارجی خصوصی
    
    pub extern stdin: void*; // نماد خارجی عمومی
    

    ثابت‌های زمان کامپایل و متغیرهای سراسری زمان اجرا

    کوروش بین ثابت‌های زمان کامپایل و متغیرهای سراسری زمان اجرا تمایز قائل می‌شود.

    • یک اعلان const در سطح بالا یک ثابت زمان کامپایل ایجاد می‌کند. مقدار آن باید در زمان کامپایل مشخص باشد و می‌توان از آن در هر عبارت زمان‌کامپایلی مانند اندازه آرایه یا پارامترهای نوع استفاده کرد.
    const MAX_SIZE = 1024;
    
    pub fn main() {
        var buffer: uint8[MAX_SIZE]; // OK: MAX_SIZE قابل ارزیابی در زمان کامپایل است
    }
    
    • یک اعلان static یک متغیر سراسری زمان اجرا ایجاد می‌کند که در باینری وجود دارد. حتی اگر static const اعلان شود، مقدار در بخش داده ذخیره می‌شود و برای ارزیابی در زمان کامپایل در دسترس نیست.
    static const PAGE_SIZE: int32 = 4096;
    
    pub fn main() {
        var arr: int32[PAGE_SIZE]; // خطا: PAGE_SIZE یک متغیر زمان اجرا است
    }
    

    می‌توانید از static var برای حالت سراسری تغییرپذیر استفاده کنید:

    static var counter: int32 = 0;
    
    pub fn increment() {
        counter += 1;
    }
    

    نکته مهم: اعلان یک متغیر سراسری با var ساده (بدون const یا static) نامعتبر است:

    var foo = 0; // خطا: متغیرهای سراسری تغییرپذیر باید با `static` اعلان شوند
    

    این محدودیت از بروز عوارض جانبی احتمالی در طول ارزیابی زمان کامپایل جلوگیری می‌کند و زبان را ایمن و قابل پیش‌بینی نگه می‌دارد.

    اصلاح‌کننده‌های متغیرهای ایستا

    متغیرهای ایستا (هم static const و هم static var) از چندین اصلاح‌کننده پشتیبانی می‌کنند که پیوند (linkage)، دید، مکان‌دهی و سایر ویژگی‌ها را کنترل می‌کنند. این اصلاح‌کننده‌ها پیش از کلیدواژه static قرار می‌گیرند.

    | اصلاح‌کننده | توضیح | سکو (Platform) | |------------------|-----------------------------------------------------------------------|----------------| | weak | نماد را ضعیف (weak) علامت‌گذاری می‌کند و امکان تعریف‌های چندگانه بدون تداخل را فراهم می‌آورد. | همه | | dllimport | نماد را از یک کتابخانه پیوند پویا (DLL) وارد می‌کند. | ویندوز | | dllexport | نماد را برای استفاده در یک کتابخانه پیوند پویا صادر می‌کند. | ویندوز | | section("name")| متغیر را در بخش خاصی (مثلاً .data یا .bss) قرار می‌دهد. | همه | | placement | (برای استفادهٔ آینده محفوظ است) مکان‌دهی حافظه سفارشی را مشخص می‌کند. | — | | linkage | (برای استفادهٔ آینده محفوظ است) رفتار پیوند را کنترل می‌کند. | — |

    مثال‌ها:

    // نماد ضعیف (اجازهٔ تعریف‌های چندگانه)
    weak static const fallback_value: int32 = 0;
    
    // وارد کردن از یک DLL
    dllimport static var external_counter: int32 = 0;
    
    // صادر کردن به یک DLL
    dllexport static var internal_state: int32 = 0;
    
    // قرار دادن در بخش سفارشی
    section(".my_data") static var cache: int32 = 0;
    

    این اصلاح‌کننده‌ها اختیاری هستند و در صورت معنی‌دار بودن می‌توان آنها را ترکیب کرد (مثلاً weak dllexport static var ...)، اما در دسترس بودن و رفتار آنها به سکوی هدف بستگی دارد.

    متغیرهای محلی

    متغیرهای محلی درون بدنه توابع با استفاده از var یا const اعلان می‌شوند. scope آنها به بلوکی که در آن تعریف شده‌اند محدود می‌شود.

    pub fn main() {
        var name = "Cyrus"; // محلی تغییرپذیر
    
        const timeout_ms = 500; // محلی تغییرناپذیر
    }
    

    اگر نیاز به اطمینان از یک نوع خاص دارید، می‌توانید اعلان را حاشیه‌نویسی کنید:

    pub fn main() {
        const epsilon: float64 = 0.001;
    
        var retries: int32;
    }
    

    مقداردهی اولیه صفر (Zero Initialization)

    در کوروش، هر متغیری که بدون مقدار اولیه صریح اعلان شود، به طور خودکار با صفر مقداردهی اولیه می‌شود.

    pub fn main() {
        var x: int32; // مقداردهی به ۰
        var y: float64; // مقداردهی به ۰.۰
        var z: void*; // مقداردهی به (nil)
    
        printf("%d\n", x);
    }
    

    مقداردهی اولیهٔ تعریف‌نشده (Undefined Initialization)

    در برخی موارد ممکن است بخواهید متغیری را بدون مقداردهی اولیه با صفر اعلان کنید. کوروش کلیدواژهٔ undefined را فراهم می‌کند تا به صراحت نشان دهد که متغیر باید بدون مقدار اولیه باقی بماند.

    pub fn main() {
        var x: int32 = undefined; // x مقداردهی اولیه با صفر نمی‌شود
        var buffer: uint8[1024] = undefined; // buffer حاوی داده‌های آشغال است
    }
    

    این ویژگی برای متغیرهای محلی و همچنین متغیرهای سراسری ایستا کار می‌کند:

    static var global_counter: int32 = undefined; // متغیر سراسری بدون مقدار اولیه صفر
    

    استفاده از undefined در کدهای حساس به عملکرد مفید است، جایی که بلافاصله قبل از خواندن، مقداردهی انجام می‌شود و از هزینه‌ی اضافی صفر کردن اولیه جلوگیری می‌کند.

    مهم: خواندن از یک متغیر undefined پیش از تخصیص مقدار به آن، رفتار تعریف‌نشده (undefined behavior) ایجاد می‌کند. از این ویژگی با دقت استفاده کنید و فقط زمانی که مطمئن هستید متغیر قبل از استفاده مقداردهی می‌شود.

    pub fn main() {
        var x: int32 = undefined;
    
        // هرگز x را اینجا نخوانید - رفتار تعریف‌نشده!
        // printf("%d\n", x); // اشتباه!
    
        x = 42; // اکنون استفاده از آن ایمن است
        printf("%d\n", x); // OK
    }
    

    اگر به متغیری نیاز دارید که مقدار اولیه‌اش تضمین شده باشد، بهتر است از یک مقداردهنده صریح استفاده کنید یا به مقداردهی صفر اتکا کنید، نه undefined.

    عدم استنتاج نوع دیرهنگام

    کوروش استنتاج نوع دیرهنگام را مجاز نمی‌داند. هر متغیر باید نوع خود را در نقطه اعلان مشخص داشته باشد، یا:

    • از طریق یک مقداردهنده اولیه (عبارت دارای نوع مشخصی است)
    • از طریق یک حاشیه‌نویسی نوع صریح

    اعلان یک متغیر بدون نوع و بدون مقداردهنده اولیه مجاز نیست، حتی اگر بعداً به آن مقدار تخصیص دهید:

    var x; // خطا!
    
    x = 10;
    

    شما باید یا بنویسید:

    var x = 10; // نوع از مقدار اولیه استنتاج می‌شود (int32)
    

    یا:

    var x: int32; // نوع صریح، با صفر مقداردهی اولیه می‌شود
    
    x = 10;