<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x635;&#x641;&#x62D;&#x647; &#x627;&#x635;&#x644;&#x6CC;: برنامه نویسی</title><link>https://sinajalalvandi.ir/blog/programming/?d=6</link><description>&#x635;&#x641;&#x62D;&#x647; &#x627;&#x635;&#x644;&#x6CC;: برنامه نویسی</description><language>fa</language><item><title>&#x627;&#x644;&#x6AF;&#x648;&#x6CC; Typestate &#x62F;&#x631; Rust: &#x627;&#x646;&#x62A;&#x642;&#x627;&#x644; &#x62E;&#x637;&#x627;&#x647;&#x627;&#x6CC; &#x645;&#x646;&#x637;&#x642;&#x6CC; &#x627;&#x632; &#x632;&#x645;&#x627;&#x646; &#x627;&#x62C;&#x631;&#x627; &#x628;&#x647; &#x632;&#x645;&#x627;&#x646; &#x6A9;&#x627;&#x645;&#x67E;&#x627;&#x6CC;&#x644;</title><link>https://sinajalalvandi.ir/blog/programming/%D8%A7%D9%84%DA%AF%D9%88%DB%8C-typestate-%D8%AF%D8%B1-rust-%D8%A7%D9%86%D8%AA%D9%82%D8%A7%D9%84-%D8%AE%D8%B7%D8%A7%D9%87%D8%A7%DB%8C-%D9%85%D9%86%D8%B7%D9%82%DB%8C-%D8%A7%D8%B2-%D8%B2%D9%85%D8%A7%D9%86-%D8%A7%D8%AC%D8%B1%D8%A7-%D8%A8%D9%87-%D8%B2%D9%85%D8%A7%D9%86-%DA%A9%D8%A7%D9%85%D9%BE%D8%A7%DB%8C%D9%84-r48/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2026_02/lYy47.jpg.84f3cd885a58119e5f667f0190099b16.jpg" /></p>
<p>در دنیای برنامه‌نویسی، همه ما با باگ‌هایی دست و پنجه نرم کرده‌ایم که ناشی از «وضعیت اشتباه» (Invalid State) هستند. مثلاً تلاش برای ارسال داده از طریق یک اتصال (Connection) که هنوز باز نشده، یا فراخوانی متد publish() روی مقاله‌ای که هنوز محتوایی ندارد. در اکثر زبان‌ها، ما این مشکل را با استفاده از شرط‌ها (if/else) یا استثناها (Exceptions) در زمان اجرا (Runtime) مدیریت می‌کنیم.</p><p>اما در زبان Rust، ما ابزاری قدرتمندتر داریم: <strong>سیستم تایپ</strong>. الگوی <strong>Typestate</strong> به ما اجازه می‌دهد تا قوانین منطقی برنامه‌مان را مستقیماً در سیستم تایپ کدگذاری کنیم. به زبان ساده، با این الگو کاری می‌کنیم که کدهای غیرمنطقی اصلاً <strong>کامپایل نشوند</strong>.</p><h3>مشکل: مدیریت وضعیت با Enumها</h3><p>روش سنتی برای مدیریت وضعیت، استفاده از یک فیلد ساده یا یک Enum است. مثال زیر را در نظر بگیرید:</p><p></p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>enum State { Draft, Review, Published }

struct Post {
    content: String,
    state: State,
}

impl Post {
    fn publish(&amp;mut self) {
        if let State::Review = self.state {
            self.state = State::Published;
            println!("Post published!");
        } else {
            panic!("Cannot publish a post that isn't in review!");
        }
    }
}</code></pre><p>در این کد، اگر برنامه‌نویس دیگری متد publish را روی یک پست در وضعیت Draft صدا بزند، برنامه در زمان اجرا کرش می‌کند. اینجاست که Typestate وارد عمل می‌شود تا این خطا را به مرحله کامپایل منتقل کند.</p><h3>الگوی Typestate چیست؟</h3><p>الگوی Typestate یعنی استفاده از انواع داده‌ای (Types) متفاوت برای نمایش وضعیت‌های مختلف یک شیء. به جای اینکه یک ساختار ثابت داشته باشیم که یک فیلد state داخلی دارد، ما برای هر وضعیت یک ساختار مجزا تعریف می‌کنیم.</p><p>این الگو در Rust به دلیل دو ویژگی کلیدی بسیار قدرتمند عمل می‌کند:</p><ol><li><p><strong>Ownership (مالکیت):</strong> وقتی یک متد شیء را مصرف می‌کند (Move)، آن وضعیت دیگر در دسترس نیست.</p></li><li><p><strong>Generics:</strong> اجازه می‌دهد کد تمیز و بازیافت‌پذیر بنویسیم.</p></li></ol><h3>پیاده‌سازی گام‌به‌گام</h3><p>بیایید مثال مدیریت پست وبلاگ را با Typestate بازنویسی کنیم.</p><h4>گام اول: تعریف وضعیت‌ها</h4><p>ابتدا برای هر وضعیت یک Struct خالی تعریف می‌کنیم. این‌ها فقط نقش «نشانگر» (Marker) را دارند.</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>struct Draft;
struct Boxed;
struct Published;</code></pre><h4>گام دوم: ساختار Generic</h4><p>حالا ساختار اصلی را طوری تعریف می‌کنیم که یک پارامتر نوع (Generic) بپذیرد:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>struct Post&lt;S&gt; {
    content: String,
    _state: std::marker::PhantomData&lt;S&gt;,
}</code></pre><p><em>(نکته: PhantomData به کامپایلر می‌گوید که ما از S استفاده منطقی می‌کنیم، بدون اینکه فضایی در حافظه اشغال شود).</em></p><h4>گام سوم: پیاده‌سازی متدهای اختصاصی هر وضعیت</h4><p>حالا جادوی اصلی اتفاق می‌افتد. ما متدهایی می‌نویسیم که فقط برای وضعیت‌های خاصی در دسترس هستند:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>impl Post&lt;Draft&gt; {
    pub fn new(content: String) -&gt; Post&lt;Draft&gt; {
        Post {
            content,
            _state: std::marker::PhantomData,
        }
    }

    pub fn request_review(self) -&gt; Post&lt;Boxed&gt; {
        Post {
            content: self.content,
            _state: std::marker::PhantomData,
        }
    }
}

impl Post&lt;Boxed&gt; {
    pub fn publish(self) -&gt; Post&lt;Published&gt; {
        println!("Post is now live!");
        Post {
            content: self.content,
            _state: std::marker::PhantomData,
        }
    }
}</code></pre><h3>چرا این روش انقلابی است؟</h3><p>۱. <strong>حذف خطاهای زمان اجرا:</strong><br>در کد بالا، متد publish فقط در impl Post&lt;Boxed&gt; تعریف شده است. اگر سعی کنید روی یک Post&lt;Draft&gt; متد publish را صدا بزنید، با این خطای کامپایلر مواجه می‌شوید:<br>no method named 'publish' found for struct 'Post&lt;Draft&gt;'</p><p>۲. <strong>تغییر وضعیت تخریب‌گر (Destructive State Transitions):</strong><br>دقت کنید که متدها self را می‌گیرند (بدون &amp;). این یعنی وقتی request_review صدا زده می‌شود، شیء قبلی (که در وضعیت Draft بود) <strong>Move</strong> می‌شود و از بین می‌رود. شما دیگر نمی‌توانید تصادفاً از شیء قدیمی استفاده کنید.</p><p>۳. <strong>هزینه صفر (Zero-Cost Abstraction):</strong><br>تمام این بررسی‌ها در زمان کامپایل انجام می‌شود. در زمان اجرا، هیچ اثری از این ساختارهای اضافه نیست و برنامه دقیقاً با همان سرعتی اجرا می‌شود که انگار از هیچ الگویی استفاده نکرده‌اید.</p><h3>چه زمانی از Typestate استفاده کنیم؟</h3><p>این الگو برای موارد زیر فوق‌العاده است:</p><ul><li><p><strong>پروتکل‌های شبکه:</strong> (مثلاً ابتدا Connect سپس Authenticate و بعد SendData).</p></li><li><p><strong>ساختن اشیاء پیچیده (Builder Pattern):</strong> وقتی که باید حتماً فیلدهای X و Y مقداردهی شوند تا بتوان متد build را صدا زد.</p></li><li><p><strong>درایورهای سخت‌افزار:</strong> مثلاً یک پین GPIO که باید ابتدا به عنوان Output تنظیم شود تا بتوان روی آن Write کرد.</p></li></ul><h3>چالش‌ها و محدودیت‌ها</h3><p>با وجود قدرت بالا، Typestate چالش‌هایی هم دارد:</p><ul><li><p><strong>تکرار کد (Boilerplate):</strong> ممکن است مجبور شوید برای هر انتقال وضعیت، یک متد جدید بنویسید و داده‌ها را از ساختار قدیم به جدید کپی کنید.</p></li><li><p><strong>پیچیدگی در مجموعه (Collections):</strong> ذخیره کردن لیستی از پست‌ها با وضعیت‌های مختلف در یک Vec سخت می‌شود (چون تایپ‌های متفاوتی دارند)، مگر اینکه از Enum یا Trait Object استفاده کنید که بخشی از امنیت زمان کامپایل را فدا می‌کند.</p></li></ul><h3>نتیجه‌گیری</h3><p>الگوی Typestate یکی از زیباترین جلوه‌های فلسفه "Correctness by Construction" در زبان Rust است. این الگو به ما یاد می‌دهد که به جای نوشتن تست‌های واحد (Unit Tests) بی‌شمار برای چک کردن وضعیت‌های غیرمجاز، می‌توانیم معماری برنامه را طوری طراحی کنیم که ایجاد وضعیت غیرمجاز اصلاً <strong>غیرممکن</strong> باشد.</p>]]></description><guid isPermaLink="false">48</guid><pubDate>Sat, 28 Feb 2026 06:38:42 +0000</pubDate></item><item><title>Rust&#x60C; Garbage Collector &#x648; &#x645;&#x62F;&#x6CC;&#x631;&#x6CC;&#x62A; &#x62F;&#x633;&#x62A;&#x6CC; &#x62D;&#x627;&#x641;&#x638;&#x647;: &#x645;&#x642;&#x627;&#x6CC;&#x633;&#x647;&#x200C;&#x627;&#x6CC; &#x641;&#x646;&#x6CC; &#x648; &#x6A9;&#x627;&#x631;&#x628;&#x631;&#x62F;&#x6CC;</title><link>https://sinajalalvandi.ir/blog/programming/rust%D8%8C-garbage-collector-%D9%88-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AF%D8%B3%D8%AA%DB%8C-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-%D9%85%D9%82%D8%A7%DB%8C%D8%B3%D9%87%E2%80%8C%D8%A7%DB%8C-%D9%81%D9%86%DB%8C-%D9%88-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF%DB%8C-r44/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_10/creative-minds-factory-YLzJtu-Vmmo-unsplash.jpg.7a05f02cec2297e8172d512ad7d77a72.jpg" /></p>
<p>مدیریت حافظه یکی از مهم‌ترین چالش‌های برنامه‌نویسی سیستم‌ها و نرم‌افزارهای پرکاربرد است. انتخاب روش مناسب می‌تواند تاثیر مستقیم بر <strong>کارایی، ایمنی و قابلیت نگهداری برنامه</strong> داشته باشد. در این مقاله قصد داریم سه رویکرد اصلی مدیریت حافظه را بررسی کنیم: <strong>Manual Memory Management</strong>، <strong>Garbage Collector</strong> و سیستم نوآورانه Rust با<a rel="" href="https://sinajalalvandi.ir/blog/programming/%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-ownership-%D9%88-borrowing-%D8%AF%D8%B1-rust-%DA%A9%D9%84%DB%8C%D8%AF-%D8%A7%D9%85%D9%86%DB%8C%D8%AA-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-%D9%88-%D8%B9%D9%85%D9%84%DA%A9%D8%B1%D8%AF-%D8%A8%D9%87%DB%8C%D9%86%D9%87-r14/"> <strong>Ownership و Borrowing</strong>.</a> همچنین مزایا، معایب و موارد استفاده هر روش را با نگاه به دنیای واقعی و پروژه‌های عملی مقایسه می‌کنیم.</p><p></p><p><a href="https://sinajalalvandi.ir/uploads/monthly_2025_10/1_Y4wP-VEkIvUQlIy3TsJtwg.png.7edfd3603589a78415676dba1be5e02f.png" class="ipsAttachLink ipsAttachLink_image ipsRichText__align--block" data-fileid="52" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="52" src="https://sinajalalvandi.ir/uploads/monthly_2025_10/1_Y4wP-VEkIvUQlIy3TsJtwg.thumb.png.241532be691e641baeb41459d87cca1f.png" alt="1_Y4wP-VEkIvUQlIy3TsJtwg.png" title="" width="1000" height="439" loading="lazy"></a></p><p></p><h3>مدیریت دستی حافظه (Manual Memory Management)</h3><p>روش کلاسیک مدیریت حافظه، همان تکنیکی است که زبان‌هایی مثل C و C++ از آن استفاده می‌کنند. در این رویکرد، برنامه‌نویس مسئول تمام تخصیص‌ها و آزادسازی حافظه است. به عبارت دیگر، شما خودتان باید بدانید چه زمانی یک بلوک حافظه را اختصاص دهید (<code>malloc</code>/<code>new</code>) و چه زمانی آزاد کنید (<code>free</code>/<code>delete</code>).</p><h5>مزایا:</h5><ul><li><p><strong>کنترل کامل:</strong> برنامه‌نویس می‌تواند دقیقاً تصمیم بگیرد چه مقدار حافظه و کجا استفاده شود.</p></li><li><p><strong>کارایی بالا:</strong> به دلیل نبود لایه اضافی برای مدیریت حافظه، سرعت اجرا تقریباً بهینه است.</p></li></ul><h5>معایب:</h5><ul><li><p><strong>خطر خطای انسانی:</strong> فراموش کردن آزادسازی حافظه منجر به <strong>Memory Leak</strong> و استفاده نادرست می‌شود.</p></li><li><p><strong>Dangling Pointers:</strong> استفاده از حافظه آزاد شده می‌تواند باعث کرش برنامه شود.</p></li><li><p><strong>کد پیچیده‌تر:</strong> هرچقدر برنامه بزرگ‌تر شود، مدیریت دستی حافظه به شدت دشوار و مستعد خطا است.</p></li></ul><h5>مثال ساده در C:</h5><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>int* ptr = malloc(sizeof(int) * 10);
// فراموش کردن free(ptr) =&gt; memory leak
free(ptr);
</code></pre><p>همانطور که مشاهده می‌کنید، اگر <code>free(ptr)</code> فراموش شود، حافظه دیگر قابل استفاده نیست و Leak رخ می‌دهد. در پروژه‌های بزرگ، این مسئله می‌تواند به مشکلات جدی و ناپایداری سیستم منجر شود</p><h3>Garbage Collector (GC</h3><p>Garbage Collector یا GC، روشی است که در زبان‌هایی مثل Java، C# و Go استفاده می‌شود. این سیستم حافظه‌ای که دیگر توسط برنامه مورد استفاده نیست را به صورت خودکار آزاد می‌کند.</p><h5>مزایا:</h5><ul><li><p><strong>ایمنی حافظه بالا:</strong> احتمال بروز Memory Leak و استفاده از حافظه آزاد شده کاهش می‌یابد.</p></li><li><p><strong>کدنویسی ساده‌تر:</strong> برنامه‌نویس نیازی به نگرانی مستقیم درباره آزادسازی حافظه ندارد.</p></li></ul><h5>معایب:</h5><ul><li><p><strong>Overhead اجرا:</strong> GC منابع CPU و حافظه مصرف می‌کند و ممکن است باعث pause یا لگ در برنامه شود.</p></li><li><p><strong>پیش‌بینی‌ناپذیری:</strong> زمان آزادسازی حافظه قابل کنترل دقیق نیست و در سیستم‌های realtime مشکل ایجاد می‌کند.</p></li><li><p><strong>کمتر مناسب برای Low-Level:</strong> در پروژه‌هایی که نیاز به کنترل مستقیم سخت‌افزار یا latency بسیار کم دارند، GC محدودیت ایجاد می‌کند.</p></li></ul><h5>مثال Java:</h5><pre spellcheck="" class="ipsCode language-java" data-language="Java"><code>Object obj = new Object();
// وقتی obj دیگر استفاده نشود، GC خودش حافظه را آزاد می‌کند
</code></pre><p>مزیت اصلی این رویکرد این است که برنامه‌نویس تمرکز بیشتری روی منطق برنامه دارد و خطرات ناشی از مدیریت دستی حافظه کاهش پیدا می‌کند. با این حال، اجرای GC می‌تواند گاهی غیرقابل پیش‌بینی و سنگین باشد.</p><h3>Rust و سیستم Ownership</h3><p>Rust یک رویکرد کاملاً متفاوت ارائه می‌دهد که ترکیبی از <strong>سرعت بالا و ایمنی حافظه</strong> است، بدون اینکه نیاز به Garbage Collector باشد. فلسفه Rust بر اساس سه مفهوم کلیدی است: <strong>Ownership</strong>، <strong>Borrowing</strong> و <strong>Lifetimes</strong>.</p><h5>چگونه کار می‌کند:</h5><ul><li><p>هر داده یک <strong>مالک (owner)</strong> دارد.</p></li><li><p>زمانی که مالک از Scope خارج شود، حافظه به صورت خودکار آزاد می‌شود.</p></li><li><p>Borrowing اجازه می‌دهد داده‌ها به اشتراک گذاشته شوند بدون ایجاد مشکلات dangling pointer.</p></li><li><p>Lifetimes تضمین می‌کند که referenceها فقط به طول عمر معتبر دسترسی داشته باشند.</p></li></ul><h5>مزایا:</h5><ul><li><p><strong>سرعت و کارایی مشابه C/C++:</strong> هیچ overhead ناشی از GC وجود ندارد.</p></li><li><p><strong>ایمنی حافظه Compile-Time:</strong> اکثر باگ‌های حافظه قبل از اجرای برنامه شناسایی می‌شوند.</p></li><li><p><strong>قابل پیش‌بینی بودن:</strong> مدیریت حافظه به صورت deterministic انجام می‌شود.</p></li></ul><h5>معایب:</h5><ul><li><p><strong>یادگیری سخت‌تر:</strong> مفاهیم Ownership و Borrowing نیازمند تمرین و درک دقیق هستند.</p></li><li><p><strong>گاهی نیاز به unsafe:</strong> برای کنترل Low-Level دقیق، برنامه‌نویس ممکن است از <code>unsafe</code> استفاده کند.</p></li></ul><h5>مثال Rust:</h5><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>fn main() {
    let v = vec![1, 2, 3]; // v مالک حافظه است
} // با خروج از scope، حافظه به صورت خودکار آزاد می‌شود
</code></pre><p>این مدل باعث می‌شود که برنامه‌نویس بدون GC و بدون نگرانی از memory leak یا dangling pointer، کدی امن و پرسرعت بنویسد.</p><h4>جدول مقایسه سریع</h4><div class="ipsRichText__table-wrapper"><table style="min-width: 80px;"><colgroup><col style="min-width:20px;"><col style="min-width:20px;"><col style="min-width:20px;"><col style="min-width:20px;"></colgroup><tbody><tr><th colspan="1" rowspan="1"><p>معیار</p></th><th colspan="1" rowspan="1"><p>Manual Memory</p></th><th colspan="1" rowspan="1"><p>Garbage Collector</p></th><th colspan="1" rowspan="1"><p>Rust (Ownership)</p></th></tr><tr><td colspan="1" rowspan="1"><p><strong>کارایی</strong></p></td><td colspan="1" rowspan="1"><p>خیلی بالا</p></td><td colspan="1" rowspan="1"><p>متوسط</p></td><td colspan="1" rowspan="1"><p>بالا</p></td></tr><tr><td colspan="1" rowspan="1"><p><strong>ایمنی حافظه</strong></p></td><td colspan="1" rowspan="1"><p>پایین</p></td><td colspan="1" rowspan="1"><p>بالا</p></td><td colspan="1" rowspan="1"><p>بالا</p></td></tr><tr><td colspan="1" rowspan="1"><p><strong>کنترل برنامه‌نویس</strong></p></td><td colspan="1" rowspan="1"><p>کامل</p></td><td colspan="1" rowspan="1"><p>محدود</p></td><td colspan="1" rowspan="1"><p>نسبی (Compile-Time)</p></td></tr><tr><td colspan="1" rowspan="1"><p><strong>پیش‌بینی‌پذیری</strong></p></td><td colspan="1" rowspan="1"><p>بالا</p></td><td colspan="1" rowspan="1"><p>کم</p></td><td colspan="1" rowspan="1"><p>بالا</p></td></tr><tr><td colspan="1" rowspan="1"><p><strong>پیچیدگی کد</strong></p></td><td colspan="1" rowspan="1"><p>بالا</p></td><td colspan="1" rowspan="1"><p>کم</p></td><td colspan="1" rowspan="1"><p>متوسط</p></td></tr></tbody></table></div><h4>جمع‌بندی</h4><p>در نهایت، انتخاب روش مدیریت حافظه بستگی به <strong>نوع پروژه، نیازهای کارایی و پیچیدگی برنامه</strong> دارد.</p><ul><li><p>اگر سرعت و کنترل کامل می‌خواهید، <strong>Manual Memory Management</strong> گزینه‌ای کلاسیک است، اما ریسک خطای انسانی بالاست.</p></li><li><p>اگر راحتی و ایمنی حافظه برایتان مهم است و کمی overhead قابل قبول است، <strong>Garbage Collector</strong> انتخاب مناسبی است.</p></li><li><p>اگر به دنبال ترکیب سرعت، ایمنی و قابلیت پیش‌بینی هستید و مایل به یادگیری مفاهیم جدید هستید، <strong>Rust با Ownership و Borrowing</strong> بهترین گزینه محسوب می‌شود.</p></li></ul><p>Rust نه تنها مشکلات GC و manual memory را حل می‌کند، بلکه به توسعه‌دهندگان امکان می‌دهد نرم‌افزارهایی سریع، امن و پایدار بنویسند؛ بدون اینکه از پیچیدگی‌های حافظه سنتی رنج ببرند. این ویژگی باعث شده Rust در سال‌های اخیر در <strong>سیستم‌های حساس، پروژه‌های وب، بازی‌سازی و embedded</strong> محبوبیت زیادی پیدا کند.</p>]]></description><guid isPermaLink="false">44</guid><pubDate>Wed, 22 Oct 2025 21:28:04 +0000</pubDate></item><item><title>&#x62F;&#x627;&#x62A; &#x646;&#x62A; 10 (.net 10): &#x628;&#x631;&#x631;&#x633;&#x6CC; &#x62A;&#x63A;&#x6CC;&#x6CC;&#x631;&#x627;&#x62A; &#x648; &#x628;&#x647;&#x628;&#x648;&#x62F;&#x647;&#x627;</title><link>https://sinajalalvandi.ir/blog/programming/%D8%AF%D8%A7%D8%AA-%D9%86%D8%AA-10-net-10-%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1%D8%A7%D8%AA-%D9%88-%D8%A8%D9%87%D8%A8%D9%88%D8%AF%D9%87%D8%A7-r42/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_09/NET-10-1.jpg.d7b8c401c4e4b1bc83fd044555a10129.jpg" /></p>
<p>با انتشار .NET 10 در نوامبر 2025 به عنوان نسخه LTS (پشتیبانی بلندمدت)، مایکروسافت بار دیگر تعهد خود را به بهبود عملکرد، امنیت و تجربه توسعه‌دهندگان نشان داد. این نسخه با مجموعه‌ای از قابلیت‌های جدید و بهینه‌سازی‌ها، توسعه اپلیکیشن‌های مدرن را سریع‌تر و کارآمدتر کرده است. در این مقاله، به بررسی تغییرات کلیدی در runtime، کتابخانه‌ها، ابزارهای توسعه، ASP.NET Core و Entity Framework Core می‌پردازیم. اگر توسعه‌دهنده .NET هستید، این مقاله شما را با ویژگی‌های جدید این نسخه آشنا خواهد کرد.</p><h3>لیست کلی تغییرات</h3><h4>1. Runtime و SDK پایه</h4><ul><li><p>بهبود عملکرد و کاهش مصرف حافظه در سناریوهای سنگین.</p></li><li><p>ارتقای ابزار CLI با امکاناتی مانند <code>--cli-schema</code> و <code>dotnet tool exec</code>.</p></li><li><p>پشتیبانی از <strong>Native AOT</strong> برای تولید برنامه‌های با سرعت بالا و مصرف پایین حافظه.</p></li></ul><h4>2. زبان C# 14</h4><ul><li><p>افزودن قابلیت‌های جدید مانند <em>field-backed properties</em> و extension blocks.</p></li><li><p>بهبود دسترسی به پارامترهای generic و امکانات پیشرفته‌تر برای لامبداها.</p></li><li><p>پشتیبانی از ویژگی‌های مدرن برای بهبود خوانایی و انعطاف‌پذیری کد.</p></li></ul><h4>3. ASP.NET Core و Blazor</h4><ul><li><p>بهبود مدیریت assetها و فشرده‌سازی خودکار در Blazor برای کاهش حجم دانلود.</p></li><li><p>افزودن قابلیت‌هایی مانند <code>RowClass</code> در QuickGrid و حفظ موقعیت اسکرول هنگام استفاده از <code>NavigateTo</code>.</p></li><li><p>پشتیبانی از <strong>passkeys</strong> برای احراز هویت بدون رمز عبور و امنیت بالاتر.</p></li><li><p>ارتقای OpenAPI به نسخه 3.1 و امکانات پیشرفته‌تر برای مستندسازی APIها.</p></li></ul><h4>4. Entity Framework Core</h4><ul><li><p>بهبود عملکرد queryها و پشتیبانی بهتر از پایگاه داده‌های مدرن مانند Azure Cosmos DB.</p></li><li><p>اضافه شدن قابلیت Vector similarity search و انعطاف بیشتر در طراحی queryها.</p></li></ul><h4>5. .NET MAUI و توسعه چندپلتفرمی</h4><ul><li><p>بهبود کنترل‌های رابط کاربری و تجربهٔ توسعه در اپلیکیشن‌های موبایل و دسکتاپ.</p></li><li><p>امکانات جدید برای telemetry، مدیریت پیکربندی و سازگاری بهتر با معماری‌های cloud-native.</p></li></ul><h4>6. Windows Forms و WPF</h4><ul><li><p>بهبود کیفیت کنترل‌های UI و ویرایش نوع UITypeEditorها.</p></li><li><p>اصلاح عملکرد clipboard و افزایش پایداری در پروژه‌های دسکتاپ.</p></li></ul><h3>جزییات تغییرات:</h3><h4>بهبودهای Runtime: عملکردی بهینه‌تر و هوشمندتر</h4><p>Runtime در .NET 10 با تمرکز بر بهینه‌سازی اجرای کد، کاهش فشار روی Garbage Collector (GC) و پشتیبانی از سخت‌افزارهای جدید، پیشرفت‌های قابل توجهی داشته است.</p><h4>بهینه‌سازی‌های JIT Compiler</h4><p>کامپایلر JIT در .NET 10 با تکنیک‌هایی نظیر <strong>devirtualization متدهای آرایه</strong> و <strong>بهبود loop inversion</strong>، عملکرد را بهبود بخشیده است. برای مثال، در حلقه‌های foreach روی آرایه‌ها، JIT حالا می‌تواند virtual callها را حذف کرده و کد را inline کند، که منجر به عملکردی مشابه حلقه‌های for می‌شود.</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>static int Sum(int[] array)
{
    int sum = 0;
    IEnumerable&lt;int&gt; temp = array;  // اکنون devirtualize می‌شود
    foreach (var num in temp)
    {
        sum += num;
    }
    return sum;
}</code></pre><p>این کد در .NET 10 تا 20% سریع‌تر اجرا می‌شود.</p><p>علاوه بر این، الگوریتم <strong>3-opt</strong> برای بهینه‌سازی layout کد استفاده شده که مسیرهای پراستفاده (hot paths) را بهینه‌تر کنار هم قرار می‌دهد و فاصله branchها را کاهش می‌دهد.</p><h4>تخصیص حافظه روی Stack</h4><p>یکی از ویژگی‌های برجسته، گسترش <strong>escape analysis</strong> برای تخصیص حافظه روی stack است. آرایه‌های کوچک از value typeها (مانند int[]) و حتی reference typeها (مانند string[]) در صورت محدود بودن scope، روی stack تخصیص می‌یابند. این قابلیت فشار روی GC را تا 15-20% کاهش می‌دهد.</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>static void Sum()
{
    int[] numbers = { 1, 2, 3 };  // تخصیص روی stack
    int sum = 0;
    for (int i = 0; i &lt; numbers.Length; i++)
    {
        sum += numbers[i];
    }
    Console.WriteLine(sum);  // خروجی: 6
}</code></pre><h4>پشتیبانی از AVX10.2 و Arm64</h4><p>.NET 10 از دستورات <strong>AVX10.2</strong> در معماری x64 پشتیبانی می‌کند (هرچند فعلاً غیرفعال است تا سخت‌افزارهای جدید عرضه شوند). همچنین، بهینه‌سازی write-barrier در Arm64 عملکرد GC را تا 8-20% بهبود داده که برای اپلیکیشن‌های موبایل و edge computing بسیار مفید است.</p><h4>کتابخانه‌ها: APIهای مدرن و امن</h4><p>کتابخانه‌های استاندارد .NET 10 با APIهای جدید در حوزه‌های امنیت، پردازش رشته‌ها و سریال‌سازی، توسعه‌دهندگان را مجهزتر کرده‌اند.</p><h4>رمزنگاری پساکوانتومی</h4><p>پشتیبانی از الگوریتم‌های <strong>post-quantum cryptography (PQC)</strong> مانند ML-KEM، ML-DSA و SLH-DSA اضافه شده است. این الگوریتم‌ها با استفاده از ویژگی IsSupported قابل بررسی هستند.</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>X509Certificate2Collection coll = store.Certificates.FindByThumbprint(HashAlgorithmName.SHA256, thumbprint);
var cert = coll.SingleOrDefault();  // استفاده از SHA-256 برای امنیت بالاتر</code></pre><h4>Globalization و پردازش رشته‌ها</h4><p>کلاس ISOWeek حالا با DateOnly سازگار است و عملیات string normalization با spans انجام می‌شود تا تخصیص حافظه کاهش یابد. همچنین، NumericOrdering در CompareOptions برای مقایسه عددی رشته‌ها اضافه شده است.</p><h4>سریال‌سازی و Collections</h4><p>OrderedDictionary&lt;TKey, TValue&gt; با متدهای TryAdd و TryGetValue بهبود یافته و برای JsonObject تا 20% سریع‌تر است. در سریال‌سازی JSON، قابلیت ReferenceHandler برای مدیریت cycleها و preset Strict برای رعایت بهترین استانداردها اضافه شده است.</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>[JsonSourceGenerationOptions(ReferenceHandler = JsonKnownReferenceHandler.Preserve)]
[JsonSerializable(typeof(SelfReference))]
internal partial class ContextWithPreserveReference : JsonSerializerContext { }</code></pre><h4>ZIP و WebSocket</h4><p>ZipArchive حالا از APIهای async پشتیبانی می‌کند و فرآیند extraction به صورت موازی انجام می‌شود. همچنین، WebSocketStream abstraction جدیدی برای WebSocketهای مبتنی بر stream ارائه می‌دهد.</p><h4>ابزارهای توسعه: ساده‌سازی فرآیندها</h4><p>SDK در .NET 10 روی ساده‌سازی توسعه و پشتیبانی از پلتفرم‌های مختلف تمرکز دارد.</p><ul><li><p><strong>حذف خودکار پکیج‌های بلااستفاده</strong>: قابلیت pruning package references به طور پیش‌فرض فعال است و زمان بیلد را کاهش می‌دهد.</p></li><li><p><strong>اجرای ابزارها بدون نصب</strong>: با dotnet tool exec می‌توانید ابزارها را بدون نصب دائم اجرا کنید.</p></li><li><p><strong>انتشار به AOT</strong>: امکان انتشار اپلیکیشن‌ها به صورت native AOT با دستور dotnet publish app.cs.</p></li><li><p><strong>ایمیج‌های کانتینری</strong>: دستور dotnet publish /t:PublishContainer برای انتشار مستقیم به container.</p></li></ul><p>همچنین، پشتیبانی از tab-completion در shellهایی مانند bash و zsh اضافه شده است.</p><h4>ASP.NET Core 10: وب سریع‌تر و امن‌تر</h4><p>ASP.NET Core 10 با بهبودهایی در Blazor، امنیت و Minimal APIs، توسعه وب را به سطح جدیدی برده است.</p><h4>Blazor: رابط کاربری پویاتر</h4><ul><li><p><strong>حالت پایدار (Persistent State)</strong>: با [PersistentState]، وضعیت کامپوننت‌ها در prerendering حفظ می‌شود.</p></li></ul><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>[PersistentState]
public List&lt;Movie&gt;? MoviesList { get; set; }
protected override async Task OnInitializedAsync()
{
    MoviesList ??= await MovieService.GetMoviesAsync();
}</code></pre><ul><li><p><strong>QuickGrid</strong>: قابلیت‌هایی مانند RowClass برای استایل‌دهی و HideColumnOptionsAsync برای بهبود UI.</p></li><li><p><strong>Response Streaming</strong>: به طور پیش‌فرض برای HttpClient فعال است.</p></li><li><p><strong>JavaScript Interop</strong>: متدهای جدید مانند InvokeConstructorAsync.</p></li></ul><h4>امنیت و احراز هویت</h4><p>پشتیبانی از <strong>passkey authentication</strong> با WebAuthn و FIDO2 برای احراز هویت بدون رمزعبور. همچنین، RedirectHttpResult.IsLocalUrl برای جلوگیری از حملات open redirect.</p><h4>Minimal APIs</h4><p>بهبودهایی در query compiler برای LINQ و پشتیبانی از OpenAPI 3.1.</p><h4>Entity Framework Core 10: دیتابیس و AI</h4><p>EF Core 10 با قابلیت‌های جدید برای AI و دیتابیس‌های مدرن طراحی شده است.</p><h4>جستجوی وکتوری و JSON</h4><p>پشتیبانی از <strong>vector data type</strong> در SQL Server 2025 و Azure SQL برای جستجوی معنایی و RAG.</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>public class Blog
{
    [Column(TypeName = "vector(1536)")]
    public SqlVector&lt;float&gt; Embedding { get; set; }
}
// جستجو:
var topSimilar = context.Blogs
    .OrderBy(b =&gt; EF.Functions.VectorDistance("cosine", b.Embedding, sqlVector))
    .Take(3).ToListAsync();</code></pre><p><strong>JSON type</strong> نیز به صورت native پشتیبانی می‌شود.</p><h4>Cosmos DB</h4><p>پشتیبانی از <strong>full-text search</strong> با EF.Functions.FullTextContains و <strong>RRF</strong> برای جستجوی هیبریدی.</p><h4>LINQ و عملیات Bulk</h4><p>بهبود translation برای joinها و ساده‌سازی bulk updates.</p><h4>چالش‌ها و نکات مهم برای مهاجرت</h4><ol><li><p><strong>سازگاری با پروژه‌های قدیمی</strong>: برخی APIها تغییر کرده یا deprecated شده‌اند و بررسی دقیق لازم است.</p></li><li><p><strong>بازنویسی بخشی از کد</strong>: استفاده از قابلیت‌های جدید Blazor و C# ممکن است نیازمند تغییر در کد باشد.</p></li><li><p><strong>یادگیری تیم توسعه‌دهنده</strong>: آشنایی با امکانات C# 14 و ویژگی‌های جدید Blazor و MAUI ضروری است.</p></li><li><p><strong>پایش و تست پس از ارتقا</strong>: مانیتورینگ و تست جامع برای اطمینان از عملکرد صحیح پروژه ضروری است.</p></li></ol><h4>نتیجه‌گیری</h4><p>.NET 10 با تمرکز بر عملکرد، امنیت و تجربه توسعه‌دهنده، ابزار قدرتمندی برای ساخت اپلیکیشن‌های مدرن ارائه می‌دهد. اگر از نسخه‌های قبلی مهاجرت می‌کنید، مستندات مایکروسافت را بررسی کنید تا با تغییرات breaking آشنا شوید. پیشنهاد می‌کنیم با یک پروژه Blazor یا قابلیت‌های vector search شروع کنید تا قدرت این نسخه را تجربه کنید.</p>]]></description><guid isPermaLink="false">42</guid><pubDate>Thu, 18 Sep 2025 21:47:00 +0000</pubDate></item><item><title>&#x633;&#x6CC; &#x634;&#x627;&#x631;&#x67E; 14:&#x648;&#x6CC;&#x698;&#x6AF;&#x6CC;&#x200C;&#x647;&#x627;&#x6CC; &#x62C;&#x62F;&#x6CC;&#x62F; &#x648; &#x6A9;&#x627;&#x631;&#x628;&#x631;&#x62F;&#x6CC; &#x628;&#x631;&#x627;&#x6CC; &#x62A;&#x648;&#x633;&#x639;&#x647;&#x200C;&#x62F;&#x647;&#x646;&#x62F;&#x6AF;&#x627;&#x646;</title><link>https://sinajalalvandi.ir/blog/programming/%D8%B3%DB%8C-%D8%B4%D8%A7%D8%B1%D9%BE-14%D9%88%DB%8C%DA%98%DA%AF%DB%8C%E2%80%8C%D9%87%D8%A7%DB%8C-%D8%AC%D8%AF%DB%8C%D8%AF-%D9%88-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF%DB%8C-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AA%D9%88%D8%B3%D8%B9%D9%87%E2%80%8C%D8%AF%D9%87%D9%86%D8%AF%DA%AF%D8%A7%D9%86-r41/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_09/596-x-334@2x-compressed.jpg.e398a92e276ecd36ea2d692f5abfdbba.jpg" /></p>
<p>در دنیای سریع‌السیر برنامه‌نویسی، زبان C# همیشه یکی از پیشتازان بوده است. مایکروسافت هر سال با معرفی نسخه‌های جدید، ابزارهایی تازه برای ساده‌سازی کد، افزایش کارایی و بهبود ایمنی ارائه می‌دهد. حالا که به سال ۲۰۲۵ رسیده‌ایم، <strong>C# 14</strong> – که بصورت preview همراه با <strong>.NET 10 </strong>معرفی شده و بصورت رسمی در نوامبر ۲۰۲۵ منتشر می‌شود – وعده تغییرات جذابی را می‌دهد. این نسخه نه تنها بر پایه تجربیات نسخه‌های قبلی مثل C# 13 ساخته شده، بلکه تمرکز ویژه‌ای روی کاهش boilerplate code، بهبود عملکرد و انعطاف‌پذیری بیشتر در نوشتن کدهای مدرن دارد.</p><p>اگر توسعه‌دهنده‌ای هستید که با <a rel="external nofollow" href="https://ASP.NET">ASP.NET</a>، Unity یا حتی اپلیکیشن‌های دسکتاپ کار می‌کنید، <strong>ویژگی‌های جدید C# 14</strong> می‌تواند workflow شما را دگرگون کند. در این مقاله، به بررسی دقیق <strong>تغییرات C# 14</strong> می‌پردازیم: از extension members گرفته تا بهبودهای lambda و span. هدف این است که نه تنها لیست ویژگی‌ها را مرور کنیم، بلکه با مثال‌های عملی و توضیحات گام‌به‌گام، بفهمیم چطور از آن‌ها در پروژه‌های واقعی استفاده کنیم. آماده‌اید؟ بیایید شروع کنیم.</p><h4>چرا C# 14 مهم است؟ نگاهی به زمینه انتشار</h4><p>قبل از غوطه‌ور شدن در جزئیات، بیایید کمی عقب برویم. C# از زمان معرفی در سال ۲۰۰۰، همیشه با .NET همگام بوده. نسخه ۱۳ در ۲۰۲۴، ویژگی‌هایی مثل primary constructors و collection expressions را آورد، اما C# 14 یک قدم جلوتر می‌رود. طبق اعلام مایکروسافت، این نسخه در <strong>نوامبر ۲۰۲۵</strong> به عنوان بخشی از <strong>.NET 10</strong> (که یک LTS یا Long-Term Support است) عرضه می‌شود. این یعنی پشتیبانی طولانی‌مدت تا سال ۲۰۲۸، که برای پروژه‌های enterprise ایده‌آل است.</p><p><strong>تغییرات C# 14</strong> عمدتاً بر سه اصل تمرکز دارند: <strong>سادگی syntax</strong>، <strong>بهبود عملکرد</strong> و <strong>ایمنی بیشتر</strong>. مثلاً، اگر قبلاً با extension methods کلنجار می‌رفتید، حالا همه چیز طبیعی‌تر شده. این تغییرات نه تنها برای تازه‌کاران مفیدند، بلکه برای veteran developerها هم ابزارهای جدیدی برای refactoring کدهای قدیمی فراهم می‌کنند. در ادامه، هر ویژگی را با مثال کد بررسی می‌کنیم – همه کدهای ارائه‌شده در Visual Studio 2022 (نسخه ۱۷.۱۲ به بعد) یا .NET 10 SDK قابل تست هستند.</p><h4>Extension Members: گسترش کلاس‌ها بدون دردسر</h4><p>یکی از ستاره‌های <strong>C# 14 new features</strong>، معرفی <strong>extension members</strong> است. قبلاً، extension methods فقط برای متدهای static محدود بودند، اما حالا می‌توانید extension properties، operators و حتی static members تعریف کنید. این ویژگی مثل این است که بگویید: "هی، این کلاس را بدون تغییر منبع اصلی، غنی‌تر کن."</p><h4>syntax جدید و مثال عملی</h4><p>فرض کنید با IEnumerable&lt;T&gt; کار می‌کنید و می‌خواهید یک property ساده مثل IsEmpty اضافه کنید. در C# 14، از بلوک extension استفاده می‌کنید:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>public static class EnumerableExtensions
{
    extension&lt;TSource&gt;(IEnumerable&lt;TSource&gt; source)
    {
        public bool IsEmpty =&gt; !source.Any();  // Property extension
    }
}</code></pre><p>حالا، در کد اصلی‌تان:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>var sequence = new List&lt;int&gt; { 1, 2, 3 };
Console.WriteLine(sequence.IsEmpty);  // خروجی: False</code></pre><p>اینجا، IsEmpty مثل یک عضو واقعی کلاس عمل می‌کند – نه مثل یک متد static که باید با نام کلاس فراخوانی شود. برای static extension members هم همین‌طور:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>extension&lt;TSource&gt;(IEnumerable&lt;TSource&gt;)
{
    public static IEnumerable&lt;TSource&gt; Identity =&gt; Enumerable.Empty&lt;TSource&gt;();
    public static IEnumerable&lt;TSource&gt; operator +(IEnumerable&lt;TSource&gt; left, IEnumerable&lt;TSource&gt; right) 
        =&gt; left.Concat(right);
}</code></pre><p>استفاده:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>var emptyList = IEnumerable&lt;int&gt;.Identity;
var combined = list1 + list2;  // Operator overloading به سبک extension</code></pre><h4>مزایا و نکات پیاده‌سازی</h4><p>این ویژگی boilerplate را کاهش می‌دهد و کد را خواناتر می‌کند. مثلاً در پروژه‌های بزرگ، جایی که LINQ extensions زیاد دارید، این کار refactoring را آسان‌تر می‌کند. فقط یادتان باشد، extension blocks باید static باشند و receiver (پارامتر اول) با this implicit کار کند.</p><p>اگر از Unity استفاده می‌کنید، تصور کنید چطور می‌توانید به GameObjectها extension property برای health اضافه کنید – بدون نیاز به inheritance پیچیده. طبق spec مایکروسافت، این ویژگی از زبان reference کامل پشتیبانی می‌کند و هیچ deprecation ای ندارد.</p><h4>کلمه کلیدی field: خداحافظی با backing fields دستی</h4><p>اگر از نوشتن private fields خسته شده‌اید، <strong>field keyword</strong> در C# 14 نجات‌دهنده شماست. این کلمه کلیدی اجازه می‌دهد accessorهای property بدون تعریف explicit backing field بنویسید – کامپایلر خودش یکی synthesize می‌کند.</p><h4>قبل و بعد: مقایسه syntax</h4><p>در نسخه‌های قبلی:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>private string _message;
public string Message
{
    get =&gt; _message;
    set =&gt; _message = value ?? throw new ArgumentNullException(nameof(value));
}</code></pre><p>در C# 14:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>public string Message
{
    get;
    set =&gt; field = value ?? throw new ArgumentNullException(nameof(value));
}</code></pre><p>ساده، نه؟ field مستقیماً به backing field اشاره می‌کند. می‌توانید فقط برای get یا set body بنویسید، و کامپایلر بقیه را هندل می‌کند.</p><h4>سناریوهای واقعی و هشدارها</h4><p>تصور کنید در یک کلاس User Profile، چندین property validation-heavy دارید. این ویژگی زمان توسعه را نصف می‌کند. اما یک نکته: اگر در scope‌تان متغیری به نام field دارید، از @field یا this.field استفاده کنید تا conflict پیش نیاید. این ویژگی preview در C# 13 بود و حالا stable است – عالی برای migration کدهای legacy.</p><p>در عمل، تست کنید: یک console app بسازید و ببینید چطور IntelliSense field را پیشنهاد می‌دهد. این تغییر کوچک، اما تأثیر بزرگی روی productivity دارد.</p><h4>Implicit Span Conversions: عملکرد بالا بدون زحمت</h4><p><strong>Span&lt;t&gt;&lt;/t&gt;</strong> و <strong>ReadOnlySpan&lt;t&gt;&lt;/t&gt;</strong> از C# 7.2 آمدند، اما C# 14 آن‌ها را first-class می‌کند. حالا implicit conversions بیشتری دارید، که کد را طبیعی‌تر و performant‌تر می‌کند – بدون allocation اضافی روی heap.</p><h4>مثال‌های کلیدی</h4><p>مثلاً، string literals حالا مستقیم به Span تبدیل می‌شوند:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>ReadOnlySpan&lt;char&gt; span = "Hello, World!";  // Implicit!
foreach (char c in span)
{
    Console.Write(c);  // بدون copy
}</code></pre><p>یا در generic methods:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>public static int SumDigits(ReadOnlySpan&lt;int&gt; numbers) =&gt; numbers.Sum();
var result = SumDigits([1, 2, 3, 4]);  // Array به Span implicit</code></pre><h4>چرا این ویژگی game-changer است؟</h4><p>در اپ‌های high-throughput مثل web servers، Spanها garbage collection را کم می‌کنند. طبق benchmarks مایکروسافت، این conversions تا ۲۰% بهبود در I/O-bound tasks می‌دهند. اگر با System.IO کار می‌کنید، این را از دست ندهید – مثلاً parsing فایل‌های بزرگ بدون bufferهای دستی.</p><p>هیچ deprecation ای نیست، اما مطمئن شوید target framework .NET 10 است.</p><h4>Unbound Generic Types در nameof: انعطاف بیشتر در reflection</h4><p>یک تغییر کوچک اما مفید: nameof حالا unbound generics را پشتیبانی می‌کند. قبلاً فقط closed types مثل List&lt;int&gt; کار می‌کرد، اما حالا List&lt;&gt; هم ok است.</p><h4>syntax و استفاده</h4><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>string typeName = nameof(List&lt;&gt;);  // خروجی: "List"
Console.WriteLine(typeName);</code></pre><h4>کاربردها</h4><p>در serialization یا logging، جایی که نام type بدون type arguments نیاز دارید، این عالی است. مثلاً در یک logger generic:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>public void Log&lt;T&gt;(T item) =&gt; Console.WriteLine($"Logging {nameof(T)}: {item}");</code></pre><p>این تغییر reflection را ساده‌تر می‌کند و کد را future-proof نگه می‌دارد.</p><h4>Simple Lambda Parameters: modifiers بدون type hassle</h4><p>Lambdas در C# همیشه قدرتمند بودند، اما حالا parameters بدون explicit type و با modifiers مثل out یا ref کار می‌کنند.</p><h4>مثال قبل و بعد</h4><p>قبلاً:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>Func&lt;string, out int, bool&gt; parse = (text, out int result) =&gt; int.TryParse(text, out result);</code></pre><p>حالا:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>Func&lt;string, out int, bool&gt; parse = (text, out result) =&gt; int.TryParse(text, out result);</code></pre><h4>فواید در LINQ و async</h4><p>در LINQ queries یا async lambdas، این syntax کوتاه‌تر است. فقط params هنوز type می‌خواهد. این ویژگی code golf را بدون از دست دادن readability ممکن می‌کند.</p><h4>Partial Members بیشتر: constructors و events partial</h4><p>C# 9 partial methods را آورد، اما C# 14 constructors و events را هم partial می‌کند. یعنی defining declaration در یک فایل، implementing در دیگری.</p><h4>برای constructors</h4><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>// File1.cs
partial class MyClass(int x)
{
    // Primary constructor partial
}

// File2.cs
partial class MyClass
{
    partial int x;  // Implementing
    partial MyClass(int x)
    {
        this.x = x &gt; 0 ? x : throw new ArgumentException();
        // Initializer فقط در implementing
    }
}</code></pre><h4>برای events</h4><p>Defining:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>partial event EventHandler MyEvent;</code></pre><p>Implementing:</p><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>partial event EventHandler MyEvent
{
    add { /* logic */ }
    remove { /* logic */ }
}</code></pre><h4>سناریوهای team development</h4><p>در تیم‌های بزرگ، این برای code generation یا generated files عالی است – مثلاً در Blazor components.</p><h4>User-Defined Compound Assignment: operators سفارشی برای += و غیره</h4><p>آخرین ویژگی: حالا می‌توانید compound assignments مثل += را user-defined کنید، با operator overloading.</p><h5>مثال</h5><pre spellcheck="" class="ipsCode language-csharp" data-language="C#"><code>public static class VectorExtensions
{
    public static Vector operator +(Vector left, Vector right) =&gt; new(left.X + right.X, left.Y + right.Y);
    
    // Compound
    public static Vector operator +(Vector left, double scalar) =&gt; new(left.X + scalar, left.Y + scalar);
}

// استفاده
Vector v = new(1, 2);
v += 3;  // Implicit به + با scalar</code></pre><p>این برای math libraries یا game physics فوق‌العاده است.</p><h4>نتیجه‌گیری: قدم بعدی برای C# developers</h4><p><strong>C# 14</strong> با این <strong>تغییرات</strong>، زبان را به سطح جدیدی می‌برد – ساده‌تر، سریع‌تر،از extension members برای غنی‌سازی APIs گرفته تا Span conversions برای performance، هر ویژگی‌ای داستانی برای گفتن دارد. اگر تازه‌کارید، از Visual Studio Insiders شروع کنید؛ اگر pro هستید، پروژه‌هایتان را migrate کنید و benchmarks بگیرید.</p><p>آینده؟ C# 15 احتمالاً روی AI integrations تمرکز دارد، اما فعلاً، C# 14 را امتحان کنید.</p><p>منابع: <a rel="external nofollow" href="https://docs.microsoft.com">docs.microsoft.com</a></p>]]></description><guid isPermaLink="false">41</guid><pubDate>Thu, 18 Sep 2025 21:26:00 +0000</pubDate></item><item><title>&#x648;&#x6CC;&#x698;&#x648;&#x627;&#x644; &#x627;&#x633;&#x62A;&#x648;&#x62F;&#x6CC;&#x648; 2026: &#x646;&#x633;&#x644;&#x6CC; &#x62C;&#x62F;&#x6CC;&#x62F; &#x627;&#x632; &#x62A;&#x648;&#x633;&#x639;&#x647; &#x646;&#x631;&#x645;&#x200C;&#x627;&#x641;&#x632;&#x627;&#x631; &#x628;&#x627; &#x642;&#x644;&#x628; &#x647;&#x648;&#x634; &#x645;&#x635;&#x646;&#x648;&#x639;&#x6CC;</title><link>https://sinajalalvandi.ir/blog/programming/%D9%88%DB%8C%DA%98%D9%88%D8%A7%D9%84-%D8%A7%D8%B3%D8%AA%D9%88%D8%AF%DB%8C%D9%88-2026-%D9%86%D8%B3%D9%84%DB%8C-%D8%AC%D8%AF%DB%8C%D8%AF-%D8%A7%D8%B2-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D8%A8%D8%A7-%D9%82%D9%84%D8%A8-%D9%87%D9%88%D8%B4-%D9%85%D8%B5%D9%86%D9%88%D8%B9%DB%8C-r40/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_09/Banner_Visual_Studio_2026_is_now_available.jpg.a73ee6ea72296cbcf3712fc9500ac50e.jpg" /></p>
<p>پس از چهار سال انتظار، مایکروسافت بالاخره ویژوال استودیو 2026 را معرفی کرد و این بار خبری از یک به‌روزرسانی معمولی نیست. این IDE جدید وعده می‌دهد که تجربه توسعه نرم‌افزار را به شکل واقعی‌ای متحول کند.</p><p><a href="https://sinajalalvandi.ir/uploads/monthly_2025_09/Screenshot2025-09-18110155.png.403a8313060ed2b2195d986e38135ea5.png" class="ipsAttachLink ipsAttachLink_image ipsRichText__align--block" data-fileid="35" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="35" src="https://sinajalalvandi.ir/uploads/monthly_2025_09/Screenshot2025-09-18110155.thumb.png.a4e251a9a850a15a67839a2f2652b5e3.png" alt="Screenshot 2025-09-18 110155.png" title="Screenshot 2025-09-18 110155.png" width="1000" height="530" loading="lazy"></a></p><h4>ادغام کامل با هوش مصنوعی</h4><p>یکی از برجسته‌ترین تغییرات ویژوال استودیو 2026، ادغام عمیق هوش مصنوعی در فرآیند توسعه است. برخلاف نسخه‌های قبلی که GitHub Copilot بیشتر یک افزونه جانبی بود، حالا AI به صورت یکپارچه در pipeline توسعه جای گرفته و با استفاده از مدل‌های پیشرفته زبان طبیعی و تحلیل کد، به توسعه‌دهنده کمک می‌کند.</p><p>این سیستم شامل یک Language Server Protocol (LSP) بهبود یافته است که قادر به درک context کامل پروژه و تحلیل real-time dependency هاست. با بهره‌گیری از الگوریتم‌های machine learning، الگوهای کدنویسی پروژه‌ها را یاد می‌گیرد و پیشنهادات خود را شخصی‌سازی می‌کند.</p><p>وقتی روی پروژه‌های جدید کار می‌کنید، محیط توسعه به صورت هوشمند شما را در درک ساختار و عملکرد کد همراهی می‌کند. همچنین می‌تواند تست‌های مناسب را بر اساس الگوهای موجود در مخزن کد پیشنهاد دهد و مستندات و توضیحات را همزمان با تغییرات کد به‌روزرسانی کند.</p><p>ویژگی «Adaptive Paste» هم قابل توجه است. این سیستم با استفاده از AST parsing و الگوریتم‌های pattern matching، قطعات کد کپی‌شده را تحلیل کرده و مطابق با code style guides، naming conventions و الگوهای معماری پروژه، تغییرات لازم را اعمال می‌کند.</p><h4>Semantic Code Analysis و IntelliSense نسل جدید</h4><p>یکی دیگر از نقاط قوت این نسخه، ارتقای چشمگیر موتور IntelliSense است. با استفاده از نسخه بهینه‌شده Roslyn Compiler Platform، این موتور قادر به تحلیل semantic عمیق‌تر کد و ارائه پیشنهادات context-aware است. همچنین پشتیبانی از cross-project type inference برای پروژه‌های multi-solution اضافه شده که کار توسعه‌دهندگان را بسیار آسان می‌کند.</p><h4>بهبود چشمگیر کارایی و سرعت</h4><p>یکی از چالش‌های همیشگی IDEها، کارایی و سرعت در پروژه‌های بزرگ است. مایکروسافت می‌گوید ویژوال استودیو 2026 در این زمینه پیشرفت قابل توجهی داشته است.</p><p>فرآیندهای اصلی توسعه شامل بارگذاری solutionها، جستجو و ناوبری در کد، عملیات Build و اجرای برنامه‌ها به شکل محسوسی سریع‌تر شده‌اند. این بهبودها برای هر دو معماری x64 و Arm64 در دسترس است.</p><p>بازخوردهای اولیه کاربران نشان می‌دهد که سرعت عملکرد در تمامی پروژه‌ها به شکل قابل توجهی افزایش یافته و تمرکز تیم توسعه روی مسائل عملکردی واقعی بوده است.</p><h4>طراحی مدرن و رابط کاربری جدید</h4><p><img class="ipsImage ipsRichText__align--block" data-fileid="34" src="https://sinajalalvandi.ir/uploads/monthly_2025_09/vs2026fluent.webp.84710acbeaf92017aa9a1742c57be011.webp" alt="vs2026fluent.webp" title="vs2026fluent.webp" width="950" height="643" loading="lazy"></p><p>ویژوال استودیو 2026 از Fluent Design System بهره می‌برد و محیط کاری متمرکزتر و آرام‌تری ایجاد کرده است. خطوط واضح‌تر، آیکن‌های بهینه‌شده و فاصله‌گذاری مناسب بین عناصر، باعث شده محیط کاری کمتر شلوغ و گیج‌کننده به نظر برسد.</p><p>پنل تنظیمات هم بازطراحی شده تا فرآیند شخصی‌سازی محیط توسعه ساده‌تر و دسترس‌پذیرتر شود. علاوه بر این، 11 طرح رنگی جدید اضافه شده که نه تنها ظاهر جذابی دارند، بلکه استانداردهای دسترسی‌پذیری را نیز رعایت می‌کنند.</p><h4>ابزارهای جدید برای تحلیل عملکرد</h4><p>Profiler Agent یکی از ابزارهای جدید و کاربردی است که می‌تواند مشکلات عملکردی را شناسایی کرده و حتی پیشنهادهایی برای بهبود ارائه دهد. این ابزار به خصوص برای توسعه‌دهندگان بازی یا اپلیکیشن‌هایی که نیاز به عملکرد بالا دارند، بسیار مفید است.</p><p>با این سیستم، دیگر نیازی به حدس زدن هنگام مواجهه با مشکلات عملکرد نیست؛ راهنمایی‌ها بر اساس traceهای واقعی و benchmarkها ارائه می‌شوند، بنابراین تغییرات با اطمینان بیشتری اعمال می‌شوند.</p><h4>بررسی هوشمند کد قبل از Pull Request</h4><p>ویژگی دیگر، تحلیل کد قبل از ارسال pull request است. این سیستم نکات قابل اجرا و عملی درباره صحت، عملکرد و امنیت کد ارائه می‌دهد و همه تحلیل‌ها روی دستگاه محلی توسعه‌دهنده انجام می‌شود.</p><p>این قابلیت باعث کاهش زمان بررسی‌های متعدد و افزایش کیفیت نهایی محصول می‌شود.</p><h4>کانال Insiders و نگاه به آینده</h4><p>مایکروسافت برای اولین بار کانال Preview را با Insiders جایگزین کرده و قصد دارد به‌روزرسانی‌های ماهانه ارائه دهد. این بروزرسانی‌ها شامل بهبود عملکرد، اصلاح طراحی و نوآوری‌های هوش مصنوعی هستند و دیگر لازم نیست سال‌ها منتظر نسخه جدید بمانید.</p><h4>نصب همزمان و سازگاری</h4><p>ویژوال استودیو 2026 می‌تواند کنار نسخه‌های قبلی نصب شود و کاربران می‌توانند componentها و تنظیمات قبلی را وارد کرده و بلافاصله کدنویسی را شروع کنند.</p><h4>جمع‌بندی</h4><p>پس از پنج سال از آخرین نسخه major، ویژوال استودیو 2026 نشان می‌دهد که مایکروسافت روی نیازهای واقعی کاربران تمرکز کرده است. ادغام عمیق هوش مصنوعی، بهبود عملکرد و طراحی مدرن همه در جهت یک هدف ساده اما قدرتمند هستند: کاهش زمان صرف‌شده برای مقابله با ابزار و تمرکز بیشتر روی حل مسائل واقعی توسعه.</p><p>البته هنوز زود است که قضاوت قطعی کرد؛ نسخه Insider در دسترس است و طی هفته‌های آینده جزئیات بیشتری منتشر خواهد شد. اما نگاه اولیه نوید یک تحول واقعی در دنیای IDEها را می‌دهد.</p>]]></description><guid isPermaLink="false">40</guid><pubDate>Thu, 18 Sep 2025 08:24:00 +0000</pubDate></item><item><title>&#x641;&#x627;&#x6CC;&#x644; llms.txt &#x686;&#x6CC;&#x633;&#x62A; &#x648; &#x686;&#x631;&#x627; &#x645;&#x647;&#x645; &#x627;&#x633;&#x62A;&#x61F;</title><link>https://sinajalalvandi.ir/blog/programming/%D9%81%D8%A7%DB%8C%D9%84-llmstxt-%DA%86%DB%8C%D8%B3%D8%AA-%D9%88-%DA%86%D8%B1%D8%A7-%D9%85%D9%87%D9%85-%D8%A7%D8%B3%D8%AA%D8%9F-r39/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_09/7352a56a-7547-4589-9f0c-1fccf99e2b8e.png.b2eff7b9211c7b39486728cd29bc8a9c.png" /></p>
<p>در دنیای وب و هوش مصنوعی، وقتی مدل‌های زبانی عظیم (Large Language Models یا به اختصار LLM) می‌خواهند مطلبی را از یک وب‌سایت بخوانند، معمولاً به مشکل می‌خورند: صفحات وب پر از المان‌هایی هستند که برای انسان مفیدند ولی برای مدل‌های زبانی مزاحمت ایجاد می‌کنند — مانند تبلیغات، منوهای ناوبری پیچیده، اسکریپت‌ها، CSSهای زیاد، و جاوااسکریپت‌هایی که محتوا را به‌صورت دینامیک بارگذاری می‌کنند. این‌ها حجم محتوا را زیاد می‌کنند و باعث می‌شوند مدل‌ها زمان یا حافظه زیادی صرف خواندن چیزهایی کنند که اغلب الزامی نیست.</p><p>اینجا دقیقاً جایی است که <strong>llms.txt</strong> کاربردی می‌شود: یک فایل متن ساده به فرمت Markdown که وب‌سایت‌ها می‌توانند در ریشه (root) دامنه‌شان قرار دهند تا به مدل‌های زبان کمک کنند سریع‌تر و بهینه‌تر بخش‌های مهم سایت را بشناسند، بدون اینکه نیاز باشد کل HTML پیچیده و ناپایدار را تفسیر کنند.</p><h4>ساختار استاندارد llms.txt</h4><p>بر اساس پیشنهاد اصلی و مقالات متعدد:</p><ol><li><p><strong>نام پروژه یا وب‌سایت</strong> — یک هِدِر سطح اول Markdown (<code># ProjectName</code>).<br>مثال:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="‏متن ساده ‏"><code># MyAwesomeWebsite
</code></pre></li><li><p><strong>خلاصه کوتاه / توضیح بلاک‌کووت</strong> — یک قطعه توضیحی در قالب Markdown که هدف وب‌سایت، کاربرانش، یا محتوای اصلی را بیان می‌کند. معمولاً بین ۱ تا چند جمله.</p></li><li><p><strong>بخش‌های مهم (Sections)</strong> — با هِدِرهای سطح دوم (<code>##</code>) که لینک‌هایی به صفحات مهم سایت با توضیح مختصر زیرشان دارند. مثلاً</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="‏متن ساده ‏"><code>## Documentation
- [Getting Started](https://example.com/docs/getting-started): how to install and begin
- [API Reference](https://example.com/docs/api): endpoints and parameters

## Blog
- [Latest Articles](https://example.com/blog): اخبار و مقالات جدید
</code></pre></li><li><p><strong>بخش‌های اختیاری (Optional)</strong> — مواردی که مهم‌اند ولی نه برای هرکاربر یا برای مدل‌ها اولویت اول را دارند؛ مثل صفحه تماس، فرصت‌های شغلی، منابع جانبی.</p></li><li><p><strong>نسخه کامل / llms-full.txt</strong> — بعضی سایت‌ها علاوه بر این فایل خلاصه، یک فایل کامل‌تر دارند به نام <code>llms-full.txt</code> که کل محتوای مستنداتی یا داکیومنت‌ها را به Markdown آورده‌اند. این نسخه برای مواقع نیاز به بافت کامل مطالب مفید است، ولی برای مدل‌های زبانی که پنجره‌ی زمینه‌ای (context window) محدود دارند باید به دقت استفاده شود.</p></li></ol><h4>تفاوت llms.txt با فایل‌های دیگر مثل robots.txt یا sitemap.xml</h4><p>برای سئوی وبلاگ و فهم بهتر:</p><div class="ipsRichText__table-wrapper"><table style="min-width: 80px;"><colgroup><col style="min-width:20px;"><col style="min-width:20px;"><col style="min-width:20px;"><col style="min-width:20px;"></colgroup><tbody><tr><th colspan="1" rowspan="1"><p>فایل</p></th><th colspan="1" rowspan="1"><p>هدف اصلی</p></th><th colspan="1" rowspan="1"><p>خواننده / مخاطب هدف</p></th><th colspan="1" rowspan="1"><p>فرمت معمول</p></th></tr><tr><td colspan="1" rowspan="1"><p><strong>robots.txt</strong></p></td><td colspan="1" rowspan="1"><p>کنترل دسترسی ربات‌ها به بخش‌های سایت (چه چیزی ایندکس شود یا نشود)</p></td><td colspan="1" rowspan="1"><p>موتورهای جستجو مانند Googlebot و سایر کراولرها</p></td><td colspan="1" rowspan="1"><p>متن ساده با فرمت مخصوص (disallow, allow…)</p></td></tr><tr><td colspan="1" rowspan="1"><p><strong>sitemap.xml</strong></p></td><td colspan="1" rowspan="1"><p>فهرست کامل یا تقریباً کامل صفحات سایت برای کمک به کراولرها برای ایندکسینگ بهتر</p></td><td colspan="1" rowspan="1"><p>موتورهای جستجو</p></td><td colspan="1" rowspan="1"><p>XML</p></td></tr><tr><td colspan="1" rowspan="1"><p><strong>llms.txt</strong></p></td><td colspan="1" rowspan="1"><p>راهنمایی مدل‌های زبان بزرگ برای فهم سریع ساختار و محتوای مهم سایت، کاهش نویز و پیچیدگی</p></td><td colspan="1" rowspan="1"><p>LLMها، ابزارهای هوش مصنوعی، جواب‌دهنده‌های خودکار</p></td><td colspan="1" rowspan="1"><p>Markdown ساده با لینک‌ها و توضیح مختصر</p></td></tr></tbody></table></div><p>چون llms.txt مخصوصِ کمک به مدل‌های هوش مصنوعی طراحی شده، باید محتوای مهم را واضح و مختصر معرفی کند و از المان‌های زائد کم کند.</p><h3>مزایا و چالش‌ها</h3><h5>مزایا</h5><ul><li><p><strong>بهبود دیده‌شدن در نتایج AI</strong>: وقتی مدل‌ها بفهمند کدام بخش‌ها برای پرسش‌هایتان مهم‌اند، احتمال اینکه در پاسخ‌ها نشان داده شوید زیادتر می‌شود.</p></li><li><p><strong>سرعت بخشی به فرایند پاسخ‌دهی AI</strong>: خواندن محتوای مهم به‌صورت مستقیم و بدون سرگردانی در المان‌های غیرضروری.</p></li><li><p><strong>کنترل بیشتر بر محتوای سایت</strong>: شما تعیین می‌کنید چه بخش‌هایی باید در معرض دید AI باشند.</p></li><li><p><strong>سازگاری بیشتر با آینده</strong>: چون استفاده از مدل‌های زبانی و جستجوی هوشمند روز به روز افزایش می‌یابد، داشتن چنین ساختاری، وب‌سایت را آماده‌تر می‌کند.</p></li></ul><h4>چالش‌ها و محدودیت‌ها</h4><ul><li><p><strong>پذیرش در میان مدل‌ها / سرویس‌ها</strong>: هنوز همه‌ی پلتفرم‌ها تضمین نکرده‌اند که llms.txt را جدی بگیرند یا بخوانند.</p></li><li><p><strong>به‌روزرسانی مستمر لازم است</strong>: اگر مطالب سایت تغییر کند و فایل llms.txt به‌روز نشود، ممکن است لینک‌ها یا توضیحات قدیمی در آن بمانند.</p></li><li><p><strong>محدودیت اندازه کامل‌ترین نسخه‌ها</strong>: فایل‌هایی مثل <code>llms-full.txt</code> ممکن است خیلی بزرگ شوند و برای مدل‌هایی با پنجره زمینه‌ای (context window) محدود قابل پردازش نباشند.</p></li><li><p><strong>خطر افشای محتوا یا تحلیل رقابتی</strong>: وقتی کل محتوای مهم سایت به سادگی قابل دسترس باشد، ممکن است رقبا بتوانند راحت‌تر آن را تحلیل کنند. این هم نکته‌ای است که باید در نظر گرفت.</p></li></ul><h4>چگونه llms.txt را بسازی و پیاده‌سازی کنی</h4><p>یه روند عملی و قدم‌به‌قدم:</p><ol><li><p><strong>لیست بخش‌های مهم سایتت را مشخص کن</strong><br>ابتدا بررسی کنید کدام صفحات واقعاً برای کاربر یا برای سؤالاتی که مدل‌های هوش مصنوعی ممکن است مطرح کنند، بسیار مهم‌اند: مستندات، مقالات کلیدی، بخش آموزش، محصولات اصلی، درباره ما، تماس، سیاست حفظ حریم خصوصی و …</p></li><li><p><strong>نوشتن فایل به فرمت Markdown استاندارد</strong><br>رعایت ساختار:</p><ul><li><p>یک هِدِر اصلی (<code>#</code>)</p></li><li><p>بلاک‌کووت با خلاصه‌ای که سایت چیست، هدف آن چیست</p></li><li><p>بخش‌ها (<code>##</code>) و لینک‌ها همراه با توضیح کوتاه</p></li><li><p>بخش اختیاری در انتها</p></li></ul></li><li><p><strong>قرار دادن فایل در ریشه دامنه</strong><br>فایل را با نام <code>llms.txt</code> در ریشه سایت (مثلاً <code>https://domain.com/llms.txt</code>) آپلود کنید تا قابل دسترسی عمومی باشد.</p></li><li><p><strong>آزمایش و تأیید</strong><br>مطمئن شوید فایل به‌صورت ساده قابل دانلود است، بدون HTML اضافی یا رندر واسطه‌ای. تست کنید لینک‌ها درست کار می‌کنند و توضیحات معنادارند.</p></li><li><p><strong>به‌روزرسانی منظم</strong><br>وقتی محتوای سایت تغییر کرد، صفحات جدید اضافه شد یا بخش‌هایی حذف شدند، فایل llms.txt را نیز به‌روزرسانی کنید.</p></li><li><p><strong>در صورت نیاز، نسخه کامل (</strong><code>llms-full.txt</code><strong>) را بساز</strong><br>اگر سایت مستندات زیاد دارد یا محتوا برای کاربران حرفه‌ای یا توسعه‌دهنده مهم است، نسخه کامل‌تر ممکن است مفید باشد، اما مراقب حجم و اندازه‌ش باشید.</p></li></ol><h4>نکات کاربردی برای بهبود سئو و افزایش خوانایی انسانی</h4><p>تا این مرحله تمرکز اصلی بر نقش <strong>llms.txt</strong> در تعامل با مدل‌های زبانی بود. با این حال، برای آنکه محتوای وب‌سایت از نظر سئو نیز جایگاه مناسبی پیدا کند و در عین حال برای خوانندگان انسانی نیز قابل استفاده و ارزشمند باشد، رعایت نکات زیر توصیه می‌شود:</p><ul><li><p>استفاده از <strong>کلمات کلیدی مرتبط</strong> مانند <em>“llms.txt”</em>، <em>“فایل ai-friendly”</em>، <em>“راهنمای هوش مصنوعی برای سایت”</em>، <em>“Markdown llms.txt”</em> و <em>“AI discovery file”</em> در عناوین اصلی و فرعی به افزایش شانس دیده‌شدن در نتایج جستجو کمک می‌کند.</p></li><li><p>به‌کارگیری <strong>لینک‌های داخلی</strong> به مقالات یا آموزش‌های مرتبط (به‌ویژه اگر پیش‌تر مطالبی درباره SEO یا هوش مصنوعی منتشر کرده‌اید) موجب بهبود ساختار سایت و افزایش زمان حضور کاربر می‌شود.</p></li><li><p>ارائه <strong>نمونه‌های عملی و قابل درک</strong> بسیار مؤثر است. برای مثال می‌توان وب‌سایتی فرضی با بخش‌های مستندات، وبلاگ و محصولات را در نظر گرفت و توضیح داد که چگونه این بخش‌ها در فایل llms.txt معرفی می‌شوند.</p></li><li><p>بیان <strong>تأثیر llms.txt بر تجربه انسانی</strong> نیز اهمیت دارد؛ چراکه این فایل تنها برای بهینه‌سازی تعامل با هوش مصنوعی نیست، بلکه می‌تواند به بهبود اعتماد مخاطب، ارتقای برندینگ و افزایش کارایی در دسترسی به محتوا نیز منجر شود.</p></li><li><p>در صورت امکان، استفاده از <strong>نمایه‌های بصری یا اسکرین‌شات</strong> از فایل llms.txt واقعی، به خوانندگان کمک می‌کند درک دقیق‌تر و ملموس‌تری از ساختار این فایل داشته باشند.</p></li></ul><h4>منابع (References)</h4><ol><li><p><a rel="external nofollow" href="https://llmstxt.org">llmstxt.org</a><a rel="external nofollow" href="https://llmstxt.org/?utm_source=chatgpt.com"> – Official Proposal for llms.txt</a></p></li><li><p><a rel="external nofollow" href="https://searchengineland.com/llms-txt-proposed-standard-453676?utm_source=chatgpt.com">Search Engine Land – “LLMs.txt proposed as new standard for guiding AI crawlers”</a></p></li><li><p><a rel="external nofollow" href="https://mintlify.com/blog/how-to-generate-llmstxt-file-automatically?utm_source=chatgpt.com">Mintlify Blog – “How to generate llms.txt file automatically”</a></p></li><li><p><a rel="external nofollow" href="https://langchain-ai.github.io/langgraph/llms-txt-overview/?utm_source=chatgpt.com">LangChain Documentation – “LLMs.txt Overview”</a></p></li><li><p><a rel="external nofollow" href="https://medium.com/data-science/llms-txt-explained-414d5121bcb3?utm_source=chatgpt.com">Medium – “LLMs.txt explained”</a></p></li><li><p><a rel="external nofollow" href="https://www.bluehost.com/blog/what-is-llms-txt/?utm_source=chatgpt.com">Bluehost Blog – “What is llms.txt?”</a></p></li></ol>]]></description><guid isPermaLink="false">39</guid><pubDate>Sun, 14 Sep 2025 17:58:00 +0000</pubDate></item><item><title>&#x622;&#x634;&#x646;&#x627;&#x6CC;&#x6CC; &#x628;&#x627; Linear Data Structure &#x62F;&#x631; &#x628;&#x631;&#x646;&#x627;&#x645;&#x647;&#x200C;&#x646;&#x648;&#x6CC;&#x633;&#x6CC;</title><link>https://sinajalalvandi.ir/blog/programming/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-linear-data-structure-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C-r35/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_09/algorithm.jpg.5d80cc105e63911af6fda7a4e3176433.jpg" /></p>
<p>در دنیای برنامه‌نویسی، داده‌ها مثل آجرهای یک ساختمان هستند؛ نحوه سازماندهی و مدیریت آن‌ها می‌تواند سرعت و کارایی برنامه‌ ما را تعیین کند. یکی از پرکاربردترین روش‌های سازماندهی داده‌ها، استفاده از <strong>Linear Data Structure</strong> است. در این مقاله، قصد داریم این مفهوم یعنی ساختار داده خطی را به زبانی ساده توضیح دهیم، انواع آن را بررسی کنیم و مثال‌هایی برای درک بهتر ارائه دهیم.</p><h2>Linear Data Structure چیست؟</h2><p>Linear Data Structure یا ساختار داده‌ی خطی، نوعی ساختار داده است که در آن عناصر به صورت <strong>خطی و ترتیبی</strong> ذخیره می‌شوند. این یعنی هر عنصر، حداکثر یک عنصر قبل و یک عنصر بعد دارد (به جز اولین و آخرین عنصر). به زبان ساده‌تر، داده‌ها مثل یک صف یا یک زنجیره پشت سر هم قرار می‌گیرند.</p><p>مزیت این ساختار این است که دسترسی و پیمایش داده‌ها ساده و قابل پیش‌بینی است. اما نقطه ضعفش این است که افزودن یا حذف عناصر می‌تواند هزینه‌بر باشد، به‌خصوص اگر بخواهید وسط زنجیره را تغییر دهید.</p><h2>انواع Linear Data Structure</h2><h3>1. Array (آرایه)</h3><p>آرایه یکی از ساده‌ترین و شناخته‌شده‌ترین ساختارهای خطی است. در آرایه، اندازه مشخص است و داده‌ها در خانه‌های پشت سر هم حافظه ذخیره می‌شوند.</p><p><strong>ویژگی‌ها:</strong></p><ul><li><p>دسترسی سریع به هر عنصر با استفاده از اندیس (Index)</p></li><li><p>اندازه ثابت (در بسیاری از زبان‌ها)</p></li><li><p>افزودن یا حذف عنصر در وسط آرایه پرهزینه است</p></li></ul><p><strong>مثال در Python:</strong></p><pre spellcheck="" class="ipsCode language-python" data-language="Python"><code># تعریف یک آرایه از اعداد
numbers = [10, 20, 30, 40, 50]

# دسترسی به عنصر سوم
print(numbers[2])  # خروجی: 30

# اضافه کردن عنصر به انتهای آرایه
numbers.append(60)
print(numbers)  # خروجی: [10, 20, 30, 40, 50, 60]
</code></pre><h3>2. Linked List (لیست پیوندی)</h3><p>لیست پیوندی از چند گره (Node) تشکیل شده است که هر گره شامل داده و اشاره‌گر به گره بعدی است. برخلاف آرایه، اندازه لیست پیوندی انعطاف‌پذیر است.</p><p><strong>ویژگی‌ها:</strong></p><ul><li><p>افزودن یا حذف عنصر در هر نقطه آسان‌تر از آرایه است</p></li><li><p>دسترسی به عناصر به صورت ترتیبی است، نه مستقیم</p></li><li><p>مصرف حافظه بیشتر به خاطر ذخیره اشاره‌گرها</p></li></ul><p><strong>مثال ساده در Python:</strong></p><pre spellcheck="" class="ipsCode language-python" data-language="Python"><code>class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        last = self.head
        while last.next:
            last = last.next
        last.next = new_node

    def print_list(self):
        current = self.head
        while current:
            print(current.data, end=" -&gt; ")
            current = current.next
        print("None")

# استفاده
llist = LinkedList()
llist.append(10)
llist.append(20)
llist.append(30)
llist.print_list()  # خروجی: 10 -&gt; 20 -&gt; 30 -&gt; None
</code></pre><p></p><h3>3. Stack (پشته)</h3><p>پشته یک ساختار داده‌ی خطی است که بر اساس قانون <strong>LIFO (Last In, First Out)</strong> عمل می‌کند؛ یعنی آخرین داده‌ای که وارد می‌شود، اولین داده‌ای است که خارج می‌شود.</p><p><strong>ویژگی‌ها:</strong></p><ul><li><p>استفاده در Undo/Redo برنامه‌ها، مدیریت حافظه و الگوریتم‌های بازگشتی</p></li><li><p>عملیات اصلی: push (اضافه کردن) و pop (حذف کردن)</p></li></ul><p><strong>مثال ساده:</strong></p><pre spellcheck="" class="ipsCode language-python" data-language="Python"><code>stack = []
stack.append(1)  # push
stack.append(2)
stack.append(3)

print(stack.pop())  # خروجی: 3
print(stack)        # خروجی: [1, 2]
</code></pre><p></p><h3>4. Queue (صف)</h3><p>صف یک ساختار داده‌ی خطی دیگر است که بر اساس قانون <strong>FIFO (First In, First Out)</strong> عمل می‌کند؛ یعنی اولین داده‌ای که وارد می‌شود، اولین داده‌ای است که خارج می‌شود.</p><p><strong>ویژگی‌ها:</strong></p><ul><li><p>استفاده در مدیریت پردازش‌ها، صف پرینترها و شبکه</p></li><li><p>عملیات اصلی: enqueue (اضافه کردن) و dequeue (حذف کردن)</p></li></ul><p><strong>مثال ساده:</strong></p><pre spellcheck="" class="ipsCode language-python" data-language="Python"><code>from collections import deque

queue = deque([1, 2, 3])
queue.append(4)      # enqueue
print(queue.popleft())  # dequeue -&gt; خروجی: 1
print(queue)           # خروجی: deque([2, 3, 4])
</code></pre><p></p><h2>جمع‌بندی</h2><p>Linear Data Structure پایه و اساس بسیاری از الگوریتم‌ها و سیستم‌های نرم‌افزاری است. انتخاب نوع ساختار مناسب بستگی به نیاز شما دارد:</p><ul><li><p>اگر سرعت دسترسی مهم است، آرایه انتخاب خوبی است.</p></li><li><p>اگر اندازه داده‌ها پویا است و تغییرات زیادی در وسط داده‌ها دارید، لیست پیوندی بهتر است.</p></li><li><p>اگر ترتیب ورود و خروج اهمیت دارد، Stack و Queue گزینه‌های عالی هستند.</p></li></ul><p>با تسلط بر این مفاهیم، شما آماده‌اید تا داده‌ها را در برنامه‌هایتان هوشمندانه مدیریت کنید و الگوریتم‌های بهینه‌تری بنویسید.</p>]]></description><guid isPermaLink="false">35</guid><pubDate>Sat, 06 Sep 2025 20:51:00 +0000</pubDate></item><item><title>Spread Operator &#x62F;&#x631; &#x62C;&#x627;&#x648;&#x627; &#x627;&#x633;&#x6A9;&#x631;&#x6CC;&#x67E;&#x62A;</title><link>https://sinajalalvandi.ir/blog/programming/spread-operator-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA-r33/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_08/65413541651.webp.55f10b3aa9db0c789cf4aa151b2e4c9b.webp" /></p>
<p>وقتی صحبت از زبان جاوا اسکریپت می‌شود، یکی از قابلیت‌هایی که در چند سال اخیر بسیار محبوب شده، <strong>Spread Operator</strong> یا همان عملگر <code>...</code> است. این عملگر ساده اما قدرتمند، می‌تواند کدنویسی شما را هم کوتاه‌تر و هم خواناتر کند. شاید در نگاه اول فقط سه نقطه‌ی ساده به نظر برسد، اما پشت همین سه نقطه، امکانات زیادی برای کار با <strong>آرایه‌ها</strong>، <strong>آبجکت‌ها</strong> و حتی <strong>توابع</strong> پنهان شده است.</p><p>در این مطلب قصد دارم به صورت کامل و مرحله به مرحله، همه چیز درباره‌ی Spread Operator در جاوا اسکریپت را توضیح بدهم. اگر تازه‌کار هستید یا حتی سال‌هاست با جاوا اسکریپت کار می‌کنید، مطمئنم نکته‌هایی پیدا می‌کنید که به کارتان بیاید.</p><h3>Spread Operator چیست؟</h3><p>Spread Operator در واقع یک سینتکس (<code>...</code>) است که به ما اجازه می‌دهد <strong>مقادیر یک آرایه یا خواص یک آبجکت</strong> را باز کنیم و در یک ساختار جدید قرار دهیم. به بیان ساده، انگار محتویات را از داخل ظرفشان بیرون می‌ریزیم و مستقیم استفاده می‌کنیم.</p><p>مثال ساده:</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const numbers = [1, 2, 3];
console.log(...numbers); // خروجی: 1 2 3
</code></pre><p>اینجا آرایه‌ی <code>numbers</code> باز شده و هر عنصر به صورت جداگانه چاپ می‌شود.</p><h3>کاربردهای Spread Operator در آرایه‌ها</h3><h4>1. کپی کردن آرایه</h4><p>قبلاً اگر می‌خواستیم یک آرایه را کپی کنیم باید از متدهایی مثل <code>slice()</code> استفاده می‌کردیم. حالا خیلی راحت با Spread:</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const arr1 = [10, 20, 30];
const arr2 = [...arr1];

console.log(arr2); // [10, 20, 30]
console.log(arr1 === arr2); // false (دو آرایه‌ی مجزا هستند)
</code></pre><p>نکته: این کپی فقط <strong>سطحی (shallow copy)</strong> است. یعنی اگر داخل آرایه آبجکت‌های تو در تو داشته باشید، فقط مرجع آن‌ها کپی می‌شود.</p><h4>2. ترکیب آرایه‌ها (Array Concatenation)</h4><p>به جای استفاده از <code>concat</code>، می‌توانیم چند آرایه را خیلی ساده ترکیب کنیم:</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const fruits = ["apple", "banana"];
const moreFruits = ["orange", "kiwi"];

const allFruits = [...fruits, ...moreFruits];
console.log(allFruits); // ["apple", "banana", "orange", "kiwi"]
</code></pre><h4>3. افزودن عناصر جدید</h4><p>با Spread می‌توانیم به راحتی مقادیری را قبل یا بعد از آرایه اضافه کنیم:</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const base = [2, 3, 4];
const extended = [1, ...base, 5];

console.log(extended); // [1, 2, 3, 4, 5]
</code></pre><hr><h3>کاربردهای Spread Operator در آبجکت‌ها</h3><p>از نسخه‌ی ES2018 به بعد، Spread Operator برای آبجکت‌ها هم معرفی شد. این یعنی حالا می‌توانیم خیلی راحت آبجکت‌ها را ترکیب یا کپی کنیم.</p><h4>1. کپی آبجکت</h4><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const user = { name: "Sara", age: 25 };
const newUser = { ...user };

console.log(newUser); // { name: "Sara", age: 25 }
console.log(user === newUser); // false
</code></pre><p>باز هم توجه داشته باشید که این کپی سطحی است.</p><h4>2. ترکیب چند آبجکت</h4><p>اگر بخواهید خصوصیات چند آبجکت را در هم ادغام کنید، Spread راه خیلی ساده‌ای است:</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const person = { name: "Ali", age: 30 };
const job = { title: "Developer", company: "TechCorp" };

const employee = { ...person, ...job };
console.log(employee);
// { name: "Ali", age: 30, title: "Developer", company: "TechCorp" }
</code></pre><h4>3. بازنویسی خصوصیات</h4><p>اگر خصوصیات مشترک داشته باشید، آخرین مقدار جلوی قبلی را می‌گیرد:</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const obj1 = { name: "Reza", age: 20 };
const obj2 = { age: 25, city: "Tehran" };

const result = { ...obj1, ...obj2 };
console.log(result); // { name: "Reza", age: 25, city: "Tehran" }
</code></pre><h3>استفاده از Spread در توابع</h3><p>یکی از جذاب‌ترین کاربردهای Spread این است که می‌توانیم عناصر یک آرایه را به عنوان ورودی‌های یک تابع پاس بدهیم.</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>function sum(a, b, c) {
  return a + b + c;
}

const nums = [5, 10, 15];
console.log(sum(...nums)); // 30
</code></pre><p>این خیلی بهتر از نوشتن <code>sum(nums[0], nums[1], nums[2])</code> است.</p><h3>تفاوت Spread Operator با Rest Parameter</h3><p>شاید کمی گیج‌کننده باشد چون هر دو با <code>...</code> نوشته می‌شوند. اما <strong>Spread</strong> و <strong>Rest</strong> دو چیز کاملاً متفاوت هستند:</p><ul><li><p><strong>Spread:</strong> برای باز کردن آرایه یا آبجکت استفاده می‌شود.</p></li><li><p><strong>Rest:</strong> برای جمع کردن چند مقدار در قالب یک آرایه استفاده می‌شود.</p></li></ul><p>مثال Rest:</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>function multiply(factor, ...numbers) {
  return numbers.map(num =&gt; num * factor);
}

console.log(multiply(2, 1, 2, 3)); // [2, 4, 6]
</code></pre><p>اینجا <code>...numbers</code> تمام ورودی‌های اضافی را در قالب یک آرایه جمع کرده است.</p><h3>محدودیت‌ها و نکات مهم Spread Operator</h3><ol><li><p><strong>کپی سطحی (Shallow Copy):</strong><br>اگر با داده‌های تو در تو (nested) سر و کار دارید، باید حواستان باشد که Spread فقط سطح اول را کپی می‌کند.</p><pre spellcheck="" class="ipsCode language-javascript" data-language="JavaScript"><code>const obj = { user: { name: "Sara" } };
const copy = { ...obj };

copy.user.name = "Ali";
console.log(obj.user.name); // "Ali" (تغییر در هر دو اعمال شده)
</code></pre></li><li><p><strong>ترتیب اهمیت دارد:</strong><br>وقتی چند آبجکت یا آرایه را ترکیب می‌کنید، ترتیب قرارگیری Spread اهمیت دارد و مقادیر بعدی روی مقادیر قبلی overwrite می‌شوند.</p></li><li><p><strong>قابل استفاده فقط در iterableها:</strong><br>برای آرایه‌ها و آبجکت‌ها کار می‌کند، ولی روی چیزهایی مثل اعداد مستقیم یا <code>null</code> جواب نمی‌دهد.</p></li></ol><h3>در نهایت</h3><p>Spread Operator در جاوا اسکریپت یک ابزار ساده اما بسیار کاربردی است که کدنویسی شما را کوتاه‌تر، تمیزتر و خواناتر می‌کند. از کپی و ترکیب آرایه‌ها و آبجکت‌ها گرفته تا ارسال آرایه به توابع، همه را می‌توان با همین سه نقطه انجام داد.</p><p>اگر تازه شروع کرده‌اید، پیشنهاد می‌کنم در پروژه‌های کوچک استفاده کنید تا به مرور دستتان بیاید. و اگر حرفه‌ای هستید، مطمئنم می‌توانید با استفاده خلاقانه از Spread Operator کدهایی بنویسید که نگه‌داری‌شان خیلی راحت‌تر باشد.</p>]]></description><guid isPermaLink="false">33</guid><pubDate>Sun, 17 Aug 2025 20:42:00 +0000</pubDate></item><item><title>&#x645;&#x631;&#x632; &#x628;&#x6CC;&#x646; Low-Level &#x648; High-Level &#x62F;&#x631; &#x632;&#x628;&#x627;&#x646; Rust &#x6A9;&#x62C;&#x627;&#x633;&#x62A;&#x61F;</title><link>https://sinajalalvandi.ir/blog/programming/%D9%85%D8%B1%D8%B2-%D8%A8%DB%8C%D9%86-low-level-%D9%88-high-level-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-rust-%DA%A9%D8%AC%D8%A7%D8%B3%D8%AA%D8%9F-r32/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_08/rust-cover-img-bw.jpg.8d9ea07b9243095501b2cb2fc1c38158.jpg" /></p>
<p>Rust زبانی‌ست که خیلی‌ها آن را «سطح پایین» می‌دانند، درحالی‌که بعضی دیگر از قدرت انتزاع‌هایش حرف می‌زنند و آن را به‌خاطر ویژگی‌های مدرنش تحسین می‌کنند. این دو دیدگاه متضاد در مورد یک زبان واحد، سؤال مهمی را مطرح می‌کند: <strong>مرز بین سطح پایین و سطح بالا در Rust دقیقاً کجاست؟</strong></p><p>در این مقاله، سعی می‌کنم این مرز را نه با تعریف‌های صرفاً تئوریک، بلکه از زاویه دید یک توسعه‌دهنده بررسی کنم؛ کسی که هم درگیر ابزارهای نزدیک به سیستم بوده، هم از امکانات سطح بالای Rust بهره برده است.</p><h3>High-Level و Low-Level: دقیقاً یعنی چه؟</h3><p>قبل از وارد شدن به جزئیات، بهتر است ابتدا نگاهی کوتاه به تعاریف بیندازیم:</p><ul><li><p><strong>زبان‌های سطح پایین (Low-Level)</strong> معمولاً کنترل دقیقی روی حافظه، مدیریت منابع، و عملکرد دارند. C و Assembly بهترین مثال‌های این دسته هستند.</p></li><li><p><strong>زبان‌های سطح بالا (High-Level)</strong> روی سادگی، انتزاع و راحتی توسعه‌دهنده تمرکز دارند. پایتون و جاوا اسکریپت در این دسته قرار می‌گیرند.</p></li></ul><p>اما Rust در این تقسیم‌بندی کلاسیک، جای مشخصی ندارد. برخلاف C، شما در Rust نیازی به free کردن حافظه ندارید، اما در عین حال هیچ Garbage Collector هم در کار نیست. شما می‌توانید در سطح انتزاع بسیار بالا کار کنید یا به کمک <code>unsafe</code> مستقیماً با اشاره‌گر خام کار کنید. این انعطاف، جایی‌ست که موضوع جالب می‌شود.</p><h3>ابزارهای سطح بالا در Rust</h3><p>Rust امکانات زیادی دارد که آن را به‌عنوان یک زبان سطح بالا مطرح می‌کند. این موارد باعث می‌شوند که توسعه‌دهندگان راحت‌تر، امن‌تر و سریع‌تر کدنویسی کنند:</p><h3>Pattern Matching</h3><p>با match و if-let و سایر ابزارهای الگو، می‌توان منطق پیچیده را به‌سادگی و خوانایی بالا پیاده‌سازی کرد.</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>match value {
    Some(v) =&gt; println!("Value is: {}", v),
    None =&gt; println!("No value."),
}</code></pre><p></p><h3>Traits و Generics</h3><p>انتزاع‌هایی شبیه به interfaces در زبان‌های دیگر، اما با کنترل بیشتر و عملکرد بهتر در زمان اجرا و کامپایل.</p><h3>Sum Types (Enums با داده متصل)</h3><p>مفهوم enum در Rust با چیزی که در C یا Java می‌بینید متفاوت است. قابلیت پیوست کردن داده به هر variant، همراه با pattern matching، ابزار بسیار قدرتمندی برای طراحی API می‌دهد.</p><h3>async/await</h3><p>پشتیبانی native از async I/O بدون نیاز به توابع بازگشتی عجیب‌وغریب یا پیچیدگی زیاد، با ترکیب دقیق کنترل و راحتی توسعه.</p><h3>ماکروهای قدرتمند</h3><p>چه ماکروهای declarative (<code>macro_rules!</code>) و چه procedural macroها، امکان تولید کد تکراری را با کنترل کامل فراهم می‌کنند.</p><h3>ابزارهای سطح پایین در Rust</h3><p>در طرف دیگر ماجرا، Rust یک زبان «سیستم» محسوب می‌شود، و دلیل خوبی هم دارد. امکاناتی که برای نزدیک شدن به سخت‌افزار و کنترل دقیق رفتار برنامه در اختیارتان می‌گذارد، در بسیاری از زبان‌های سطح بالا وجود ندارند:</p><h3>Unsafe Code</h3><p>Rust به شما اجازه می‌دهد با قرار دادن بخش‌هایی از کد در بلاک <code>unsafe</code>، به رفتارهایی خارج از سیستم بررسی ایمنی زبانی دسترسی داشته باشید؛ مثل:</p><ul><li><p>کار با اشاره‌گر خام</p></li><li><p>دسترسی مستقیم به حافظه</p></li><li><p>تعامل با کدهای C یا اسمبلی</p></li></ul><h3>Layout کنترل‌شده‌ی حافظه</h3><p>با استفاده از attributes مثل <code>#[repr(C)]</code> یا <code>#[repr(packed)]</code>، می‌توانید دقیقاً مشخص کنید که ساختار داده‌ها در حافظه چگونه چیده شوند.</p><h3>Assembly Inline</h3><p>قابلیت استفاده از کد اسمبلی مستقیماً درون کد Rust با <code>asm!</code> یا <code>llvm_asm!</code> برای کنترل دقیق روی CPU instructions.</p><h3>Manual Allocation</h3><p>با استفاده از <code>Box::into_raw()</code> و <code>Vec::with_capacity()</code> می‌توانید به‌صورت کاملاً کنترل‌شده حافظه را مدیریت کنید.</p><p></p><h3>یک مثال دوگانه: کار هم‌زمان در دو سطح</h3><p>فرض کنیم می‌خواهیم یک buffer ساده بسازیم. نسخه‌ی سطح بالا می‌تواند از <code>Vec&lt;u8&gt;</code> استفاده کند. اما اگر بخواهیم کنترل دقیق روی حافظه داشته باشیم، می‌توانیم با <code>unsafe</code> و pointerها این کار را انجام دهیم.</p><h4>نسخه‌ی High-Level:</h4><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>fn allocate_buffer(size: usize) -&gt; Vec&lt;u8&gt; {
    vec![0; size]
}</code></pre><p></p><h4>نسخه‌ی Low-Level:</h4><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>fn allocate_buffer(size: usize) -&gt; *mut u8 {
    let layout = std::alloc::Layout::from_size_align(size, 1).unwrap();
    unsafe { std::alloc::alloc(layout) }
}</code></pre><p>هر دو نسخه معتبرند. نسخه‌ی اول امن و راحت است، نسخه‌ی دوم دقیق و خطرناک.</p><h3>همزیستی به‌جای تضاد</h3><p>Rust یک زبان دوگانه نیست چون بین این دو دنیا درگیر است؛ بلکه چون راهی برای هم‌زیستی داده است. شما می‌توانید بیشتر زمان خود را در دنیای ایمن، خوانا و قابل نگهداری Rust بگذرانید، اما در لحظه‌ای که نیاز باشد، دقیقاً تا سطح سخت‌افزار پایین بروید—بدون ترک کردن زبان.</p><p>مفهومی که این تعادل را ممکن کرده، <strong>zero-cost abstraction</strong> است: امکانات سطح بالا در Rust، در بسیاری از موارد، هیچ هزینه‌ی اضافه‌ای در زمان اجرا ندارند. به زبان ساده، abstraction بدون قربانی کردن performance.</p><h3>نتیجه‌گیری</h3><p>Rust زبانی‌ست که مرز بین سطح پایین و بالا را نه تنها محو کرده، بلکه در بسیاری از موارد، این مرز را به یک قابلیت تبدیل کرده است. در جهانی که گاهی کارایی و کنترل با راحتی و ایمنی در تضادند، Rust نشان داده که می‌توان به هر دو دست یافت—اگر ابزار را خوب بشناسی.</p><p>Rust نه صرفاً یک زبان low-level است، نه صرفاً high-level. <strong>Rust یک انتخاب معماری‌ست.</strong></p>]]></description><guid isPermaLink="false">32</guid><pubDate>Fri, 08 Aug 2025 10:37:00 +0000</pubDate></item><item><title>&#x627;&#x628;&#x632;&#x627;&#x631;&#x647;&#x627; &#x648; &#x6A9;&#x62A;&#x627;&#x628;&#x62E;&#x627;&#x646;&#x647;&#x200C;&#x647;&#x627;&#x6CC; &#x633;&#x627;&#x62E;&#x62A; &#x631;&#x627;&#x628;&#x637; &#x6A9;&#x627;&#x631;&#x628;&#x631;&#x6CC; &#x6AF;&#x631;&#x627;&#x641;&#x6CC;&#x6A9;&#x6CC; &#x62F;&#x631; &#x632;&#x628;&#x627;&#x646; Rust</title><link>https://sinajalalvandi.ir/blog/programming/%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1%D9%87%D8%A7-%D9%88-%DA%A9%D8%AA%D8%A7%D8%A8%D8%AE%D8%A7%D9%86%D9%87%E2%80%8C%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%AE%D8%AA-%D8%B1%D8%A7%D8%A8%D8%B7-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%DB%8C-%DA%AF%D8%B1%D8%A7%D9%81%DB%8C%DA%A9%DB%8C-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-rust-r29/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_07/hero-banner.png.de69db05aaee02892c23d740aaaf3d0d.png" /></p>
<p>زبان برنامه‌نویسی Rust به دلیل ایمنی حافظه، عملکرد بالا، و قابلیت‌های مدرن خود به یکی از محبوب‌ترین زبان‌ها برای توسعه نرم‌افزارهای سیستمی تبدیل شده است. اگرچه Rust در ابتدا برای برنامه‌نویسی سیستمی طراحی شده بود، اما در سال‌های اخیر، ابزارها و کتابخانه‌های متعددی برای ساخت رابط‌های کاربری گرافیکی (GUI) در این زبان توسعه یافته‌اند. این مقاله به معرفی و بررسی مهم‌ترین ابزارها و کتابخانه‌های موجود برای ایجاد رابط‌های کاربری گرافیکی در Rust می‌پردازد و ویژگی‌ها، مزایا، و معایب هر یک را مورد بحث قرار می‌دهد.</p><h2>چرا رابط کاربری گرافیکی در Rust؟</h2><p>Rust با ویژگی‌هایی مانند ایمنی حافظه، عدم استفاده از زباله‌روب (Garbage Collector)، و عملکرد نزدیک به زبان‌های سطح پایین مانند C++، گزینه‌ای جذاب برای توسعه برنامه‌هایی است که نیاز به رابط کاربری گرافیکی دارند. در مقایسه با زبان‌هایی مثل پایتون که کتابخانه‌های GUI بالغی مانند Tkinter یا PyQt دارند، اکوسیستم Rust در حوزه GUI هنوز در حال توسعه است. با این حال، جامعه فعال Rust و حمایت شرکت‌هایی مانند موزیلا باعث شده تا ابزارهای قدرتمندی برای این منظور در دسترس قرار گیرند.</p><p>ساخت رابط کاربری گرافیکی در Rust می‌تواند برای پروژه‌هایی که نیاز به عملکرد بالا، امنیت حافظه، و کنترل دقیق منابع دارند، بسیار مناسب باشد. از برنامه‌های دسکتاپ گرفته تا ابزارهای چندپلتفرمی، Rust امکان توسعه برنامه‌هایی با رابط کاربری جذاب و کارآمد را فراهم می‌کند.</p><h2>معیارهای انتخاب کتابخانه GUI</h2><p>قبل از معرفی کتابخانه‌ها، مهم است که معیارهای انتخاب یک کتابخانه GUI مناسب را در نظر بگیریم:</p><ul><li><p><strong>عملکرد</strong>: کتابخانه باید با فلسفه Rust برای ارائه عملکرد بالا هم‌خوانی داشته باشد.</p></li><li><p><strong>چندپلتفرمی بودن</strong>: پشتیبانی از سیستم‌عامل‌های مختلف (ویندوز، مک، لینوکس) ضروری است.</p></li><li><p><strong>سادگی استفاده</strong>: رابط برنامه‌نویسی (API) باید کاربرپسند و هم‌راستا با سینتکس Rust باشد.</p></li><li><p><strong>جامعه و پشتیبانی</strong>: وجود مستندات جامع و جامعه فعال برای رفع مشکلات اهمیت دارد.</p></li><li><p><strong>قابلیت‌های گرافیکی</strong>: پشتیبانی از ویجت‌های متنوع، انیمیشن‌ها، و رندرینگ پیشرفته.</p></li><li><p><strong>اندازه و وابستگی‌ها</strong>: کتابخانه‌های سبک‌تر با وابستگی‌های کمتر برای پروژه‌های کوچک مناسب‌تر هستند.</p></li></ul><p>حالا به بررسی برخی از مهم‌ترین کتابخانه‌های GUI در Rust می‌پردازیم.</p><h2>1. <strong>Druid</strong></h2><p>Druid یک فریم‌ورک GUI متن‌باز است که به طور خاص برای Rust طراحی شده و بر عملکرد و سادگی تمرکز دارد. این کتابخانه توسط تیم توسعه‌دهنده Xi Editor ایجاد شده و برای ساخت برنامه‌های دسکتاپ چندپلتفرمی مناسب است.</p><h3>ویژگی‌ها:</h3><ul><li><p><strong>معماری داده‌محور</strong>: Druid از الگوی داده‌محور (data-driven) استفاده می‌کند که در آن رابط کاربری به صورت واکنشی (reactive) به تغییرات داده‌ها پاسخ می‌دهد.</p></li><li><p><strong>پشتیبانی چندپلتفرمی</strong>: روی ویندوز، مک، و لینوکس به خوبی کار می‌کند.</p></li><li><p><strong>رندرینگ پیشرفته</strong>: از موتور رندرینگ Piet استفاده می‌کند که امکان رندرینگ دوبعدی با کیفیت بالا را فراهم می‌آورد.</p></li><li><p><strong>سبک و سریع</strong>: Druid تلاش می‌کند تا با حداقل سربار، عملکردی نزدیک به زبان‌های سطح پایین ارائه دهد.</p></li></ul><h3>مزایا:</h3><ul><li><p>ادغام عالی با اکوسیستم Rust.</p></li><li><p>مستندات مناسب و جامعه رو به رشد.</p></li><li><p>مناسب برای برنامه‌های دسکتاپ با نیاز به رندرینگ گرافیکی پیشرفته.</p></li></ul><h3>معایب:</h3><ul><li><p>هنوز در مراحل اولیه توسعه است و ممکن است برخی ویژگی‌های پیشرفته GUI را نداشته باشد.</p></li><li><p>ویجت‌های آماده محدودتری نسبت به فریم‌ورک‌های بالغ مانند Qt دارد.</p></li></ul><h3>مثال استفاده:</h3><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>use druid::widget::{Button, Flex, Label};
use druid::{AppLauncher, LocalizedString, Widget, WindowDesc};

fn build_ui() -&gt; impl Widget&lt;u32&gt; {
    let text = Label::new(|data: &amp;u32, _env: &amp;_| format!("شمارنده: {}", data));
    let button = Button::new("افزایش").on_click(|_ctx, data, _env| *data += 1);
    Flex::column().with_child(text).with_child(button)
}

fn main() {
    let main_window = WindowDesc::new(build_ui()).title("برنامه ساده");
    AppLauncher::with_window(main_window)
        .launch(0)
        .expect("خطا در راه‌اندازی");
}</code></pre><h2>2. <strong>egui</strong></h2><p>egui یک کتابخانه GUI سبک و فوری (immediate mode) است که برای ساخت رابط‌های کاربری ساده و سریع مناسب است. این کتابخانه به دلیل استفاده در ابزارهای گرافیکی و بازی‌ها شناخته شده است.</p><h3>ویژگی‌ها:</h3><ul><li><p><strong>حالت فوری</strong>: برخلاف حالت‌های مبتنی بر ویجت (retained mode)، egui در هر فریم رابط کاربری را بازسازی می‌کند که این روش برای برنامه‌های پویا مناسب است.</p></li><li><p><strong>سبک و بدون وابستگی</strong>: نیازی به کتابخانه‌های سنگین خارجی ندارد.</p></li><li><p><strong>پشتیبانی از WebAssembly</strong>: امکان اجرای برنامه‌های GUI در مرورگر را فراهم می‌کند.</p></li><li><p><strong>ادغام با موتورهای بازی</strong>: به راحتی با کتابخانه‌هایی مثل wgpu یا ggez ادغام می‌شود.</p></li></ul><h3>مزایا:</h3><ul><li><p>بسیار سبک و مناسب برای پروژه‌های کوچک یا ابزارهای توسعه.</p></li><li><p>یادگیری آسان برای توسعه‌دهندگانی که با Rust آشنا هستند.</p></li><li><p>مناسب برای برنامه‌های تعاملی و گرافیکی مانند ابزارهای ویرایشگر یا داشبورد.</p></li></ul><h3>معایب:</h3><ul><li><p>ویجت‌های محدودتر نسبت به فریم‌ورک‌های سنتی.</p></li><li><p>ممکن است برای برنامه‌های پیچیده دسکتاپ مناسب نباشد.</p></li></ul><h3>مثال استفاده:</h3><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>use eframe::egui;

fn main() -&gt; Result&lt;(), eframe::Error&gt; {
    let options = eframe::NativeOptions::default();
    eframe::run_simple_native("برنامه egui", options, |ctx, _frame| {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("سلام، egui!");
            if ui.button("کلیک کنید").clicked() {
                println!("دکمه کلیک شد!");
            }
        });
    })
}</code></pre><h2>3. <strong>Slint</strong></h2><p>Slint (که قبلاً به نام SixtyFPS شناخته می‌شد) یک فریم‌ورک GUI چندپلتفرمی است که برای ساخت رابط‌های کاربری جذاب و مدرن طراحی شده است. این کتابخانه از یک زبان توصیفی (DSL) برای تعریف رابط کاربری استفاده می‌کند.</p><h3>ویژگی‌ها:</h3><ul><li><p><strong>زبان توصیفی</strong>: رابط کاربری با استفاده از یک سینتکس شبیه به QML تعریف می‌شود.</p></li><li><p><strong>پشتیبانی از WebAssembly</strong>: امکان اجرای برنامه‌ها در مرورگر.</p></li><li><p><strong>عملکرد بالا</strong>: بهینه‌سازی شده برای دستگاه‌های با منابع محدود.</p></li><li><p><strong>پشتیبانی از انیمیشن‌ها</strong>: قابلیت افزودن انیمیشن‌های پیچیده به رابط کاربری.</p></li></ul><h3>مزایا:</h3><ul><li><p>رابط کاربری زیبا و مدرن با حداقل کدنویسی.</p></li><li><p>مناسب برای برنامه‌های چندپلتفرمی و تعاملی.</p></li><li><p>مستندات خوب و جامعه رو به رشد.</p></li></ul><h3>معایب:</h3><ul><li><p>نیاز به یادگیری زبان توصیفی Slint.</p></li><li><p>هنوز به اندازه Qt یا GTK بالغ نیست.</p></li></ul><h3>مثال استفاده:</h3><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>import { Button, VerticalBox } from "slint";

MainWindow {
    title: "برنامه Slint";
    VerticalBox {
        Button {
            text: "کلیک کنید";
            clicked =&gt; { println!("دکمه کلیک شد!"); }
        }
    }
}</code></pre><p></p><h2>4. <strong>Iced</strong></h2><p>Iced یک کتابخانه GUI متن‌باز است که از معماری Elm الهام گرفته شده و برای ساخت برنامه‌های دسکتاپ و وب مناسب است. این کتابخانه بر سادگی و عملکرد تمرکز دارد.</p><h3>ویژگی‌ها:</h3><ul><li><p><strong>معماری Elm</strong>: از الگوی پیام‌محور برای مدیریت حالت استفاده می‌کند.</p></li><li><p><strong>چندپلتفرمی</strong>: پشتیبانی از ویندوز، مک، لینوکس، و WebAssembly.</p></li><li><p><strong>رندرینگ انعطاف‌پذیر</strong>: از wgpu برای رندرینگ استفاده می‌کند.</p></li><li><p><strong>جامعه فعال</strong>: به سرعت در حال توسعه و بهبود است.</p></li></ul><h3>مزایا:</h3><ul><li><p>سینتکس تمیز و قابل فهم.</p></li><li><p>مناسب برای توسعه‌دهندگانی که با معماری‌های واکنشی آشنا هستند.</p></li><li><p>پشتیبانی از WebAssembly برای برنامه‌های وب.</p></li></ul><h3>معایب:</h3><ul><li><p>ویجت‌های محدودتر نسبت به فریم‌ورک‌های قدیمی‌تر.</p></li><li><p>مستندات هنوز در حال تکمیل است.</p></li></ul><h3>مثال استفاده:</h3><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>use iced::widget::{button, column, text};
use iced::{Element, Sandbox, Settings};

#[derive(Default)]
struct Counter {
    value: i32,
}

#[derive(Debug, Clone)]
enum Message {
    Increment,
}

impl Sandbox for Counter {
    type Message = Message;

    fn new() -&gt; Self {
        Counter::default()
    }

    fn title(&amp;self) -&gt; String {
        String::from("برنامه Iced")
    }

    fn update(&amp;mut self, message: Message) {
        match message {
            Message::Increment =&gt; self.value += 1,
        }
    }

    fn view(&amp;self) -&gt; Element&lt;Message&gt; {
        column![
            text(format!("شمارنده: {}", self.value)),
            button("افزایش").on_press(Message::Increment),
        ]
        .into()
    }
}

fn main() -&gt; iced::Result {
    Counter::run(Settings::default())
}</code></pre><h2>5. <strong>GTK-rs</strong></h2><p>GTK-rs یک اتصال (binding) برای کتابخانه GTK است که به زبان C نوشته شده و یکی از محبوب‌ترین ابزارهای ساخت GUI در لینوکس است. این کتابخانه امکان استفاده از قابلیت‌های GTK را در Rust فراهم می‌کند.</p><h3>ویژگی‌ها:</h3><ul><li><p><strong>ویجت‌های غنی</strong>: مجموعه گسترده‌ای از ویجت‌های آماده برای ساخت برنامه‌های پیچیده.</p></li><li><p><strong>پشتیبانی قوی از لینوکس</strong>: به‌ویژه در محیط‌های گنوم.</p></li><li><p><strong>ادغام با Glade</strong>: امکان طراحی رابط کاربری با ابزارهای گرافیکی.</p></li></ul><h3>مزایا:</h3><ul><li><p>بسیار بالغ و پایدار.</p></li><li><p>مناسب برای برنامه‌های دسکتاپ پیچیده.</p></li><li><p>مستندات و جامعه قوی به دلیل قدمت GTK.</p></li></ul><h3>معایب:</h3><ul><li><p>وابستگی به کتابخانه‌های سیستمی که ممکن است نصب را پیچیده کند.</p></li><li><p>کمتر با فلسفه Rust هم‌خوانی دارد (به دلیل استفاده از C).</p></li></ul><h2>6. <strong>Qt (با اتصال Rust)</strong></h2><p>Qt یک فریم‌ورک قدرتمند و بالغ برای ساخت GUI است که از طریق اتصال‌هایی مانند qt-rs در Rust قابل استفاده است. این کتابخانه برای برنامه‌های دسکتاپ و موبایل مناسب است.</p><h3>ویژگی‌ها:</h3><ul><li><p><strong>ویجت‌های حرفه‌ای</strong>: مجموعه‌ای کامل از ابزارهای گرافیکی.</p></li><li><p><strong>چندپلتفرمی</strong>: پشتیبانی عالی از ویندوز، مک، لینوکس، و حتی موبایل.</p></li><li><p><strong>ابزارهای طراحی</strong>: امکان استفاده از Qt Designer برای طراحی رابط کاربری.</p></li></ul><h3>معایب:</h3><ul><li><p>اتصال‌های Rust برای Qt هنوز در حال توسعه هستند و ممکن است ناپایدار باشند.</p></li><li><p>وابستگی به کتابخانه‌های سنگین Qt.</p></li></ul><h2>نتیجه‌گیری</h2><p>اکوسیستم Rust در زمینه توسعه رابط کاربری گرافیکی در حال رشد سریع است. کتابخانه‌هایی مانند Druid، egui، Slint، و Iced هر یک ویژگی‌های منحصربه‌فردی ارائه می‌دهند که بسته به نیاز پروژه می‌توانند مناسب باشند. برای پروژه‌های سبک و سریع، egui و Iced گزینه‌های عالی هستند، در حالی که Druid و Slint برای برنامه‌های پیچیده‌تر مناسب‌اند. اگر به دنبال فریم‌ورک‌های بالغ هستید، GTK-rs و Qt می‌توانند انتخاب‌های خوبی باشند، هرچند ممکن است با پیچیدگی‌های بیشتری همراه باشند.</p><p>توصیه می‌شود قبل از انتخاب کتابخانه، نیازهای پروژه خود را به دقت بررسی کنید و مستندات و نمونه‌کدهای هر کتابخانه را آزمایش کنید. با توجه به رشد سریع جامعه Rust، انتظار می‌رود که در آینده ابزارهای بیشتری برای توسعه GUI در این زبان ارائه شوند.</p>]]></description><guid isPermaLink="false">29</guid><pubDate>Tue, 15 Jul 2025 11:25:57 +0000</pubDate></item><item><title>&#x6A9;&#x644;&#x6CC;&#x62F;&#x648;&#x627;&#x698;&#x647; volatile &#x62F;&#x631; &#x632;&#x628;&#x627;&#x646; C: &#x6CC;&#x6A9; &#x627;&#x628;&#x632;&#x627;&#x631; &#x642;&#x62F;&#x631;&#x62A;&#x645;&#x646;&#x62F; &#x648; &#x6A9;&#x645;&#x62A;&#x631; &#x634;&#x646;&#x627;&#x62E;&#x62A;&#x647;&#x200C;&#x634;&#x62F;&#x647; &#x628;&#x631;&#x627;&#x6CC; &#x628;&#x631;&#x646;&#x627;&#x645;&#x647;&#x200C;&#x646;&#x648;&#x6CC;&#x633;&#x6CC; &#x633;&#x637;&#x62D; &#x67E;&#x627;&#x6CC;&#x6CC;&#x646;</title><link>https://sinajalalvandi.ir/blog/programming/%DA%A9%D9%84%DB%8C%D8%AF%D9%88%D8%A7%DA%98%D9%87-volatile-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-c-%DB%8C%DA%A9-%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1-%D9%82%D8%AF%D8%B1%D8%AA%D9%85%D9%86%D8%AF-%D9%88-%DA%A9%D9%85%D8%AA%D8%B1-%D8%B4%D9%86%D8%A7%D8%AE%D8%AA%D9%87%E2%80%8C%D8%B4%D8%AF%D9%87-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%B3%D8%B7%D8%AD-%D9%BE%D8%A7%DB%8C%DB%8C%D9%86-r25/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_06/Volatile-in-C.jpg.741cf939240e52fda027469449fda365.jpg" /></p>
<p>زبان برنامه‌نویسی C به دلیل انعطاف‌پذیری و کنترل سطح پایینی که به برنامه‌نویس ارائه می‌دهد، یکی از محبوب‌ترین زبان‌ها برای توسعه سیستم‌های نهفته، درایورهای سخت‌افزاری و نرم‌افزارهای بلادرنگ است. اما یکی از ویژگی‌های این زبان که اغلب در آموزش‌های ابتدایی کمتر به آن پرداخته می‌شود، کلیدواژه volatile است. این کلیدواژه، که ممکن است در نگاه اول ساده به نظر برسد، نقش مهمی در بهینه‌سازی و اطمینان از عملکرد صحیح برنامه‌ها در سناریوهای خاص ایفا می‌کند. در این مقاله، به بررسی عمیق کلیدواژه volatile، کاربردهای آن، و دلایلی که هر برنامه‌نویس C باید با آن آشنا باشد، می‌پردازیم.</p><h2>volatile چیست و چرا اهمیت دارد؟</h2><p>کلیدواژه <strong>volatile</strong> در زبان C به کامپایلر اطلاع می‌دهد که مقدار یک متغیر ممکن است به‌صورت غیرمنتظره تغییر کند، حتی اگر در کد برنامه به نظر نرسد که این متغیر تغییر می‌کند. این ویژگی به‌ویژه در برنامه‌نویسی سطح پایین، مانند کار با سخت‌افزار، سیستم‌های نهفته، یا برنامه‌های چندنخی، حیاتی است. بدون استفاده از volatile، کامپایلر ممکن است بهینه‌سازی‌هایی انجام دهد که منجر به رفتار نادرست برنامه شود.</p><p>به عنوان مثال، فرض کنید متغیری دارید که مقدار آن توسط یک وقفه سخت‌افزاری یا یک رشته (thread) دیگر تغییر می‌کند. اگر این متغیر با volatile مشخص نشده باشد، کامپایلر ممکن است فرض کند که مقدار آن ثابت است و بهینه‌سازی‌هایی مانند ذخیره‌سازی مقدار در یک ثبات (register) یا حذف دسترسی‌های مکرر به آن را انجام دهد. این کار می‌تواند باعث شود که تغییرات واقعی متغیر در حافظه نادیده گرفته شوند.</p><h2>کاربردهای اصلی volatile در زبان C</h2><p>برای درک بهتر اهمیت volatile، بیایید به چند سناریوی کاربردی کلیدی نگاه کنیم:</p><h3>1. <strong>کار با سخت‌افزار و رجیسترهای حافظه</strong></h3><p>یکی از رایج‌ترین کاربردهای volatile در برنامه‌نویسی سیستم‌های نهفته است. در این سیستم‌ها، متغیرها اغلب به رجیسترهای سخت‌افزاری (مانند رجیسترهای ورودی/خروجی) نگاشت می‌شوند. این رجیسترها ممکن است توسط سخت‌افزار به‌صورت غیرمنتظره تغییر کنند. به مثال زیر توجه کنید:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>volatile int *hardware_register = (volatile int *)0x1000;</code></pre><p>در این کد، متغیر hardware_register به یک آدرس حافظه خاص اشاره دارد که ممکن است توسط سخت‌افزار تغییر کند. استفاده از volatile به کامپایلر می‌گوید که هر بار که به این متغیر دسترسی پیدا می‌کند، باید مقدار آن را مستقیماً از حافظه بخواند و نه از ثبات‌های داخلی CPU.</p><h3>2. <strong>برنامه‌نویسی چندنخی</strong></h3><p>در برنامه‌های چندنخی، متغیرهایی که بین نخ‌ها به اشتراک گذاشته می‌شوند، ممکن است به‌صورت غیرمنتظره تغییر کنند. اگر یک نخ مقداری را تغییر دهد، نخ دیگر باید به مقدار به‌روز شده دسترسی داشته باشد. بدون volatile، کامپایلر ممکن است فرض کند که متغیر در یک نخ ثابت است و بهینه‌سازی‌هایی انجام دهد که باعث از دست رفتن تغییرات شود. برای مثال:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>volatile int shared_flag = 0;

void thread1() {
    while (!shared_flag) {
        // منتظر تغییر پرچم
    }
}

void thread2() {
    shared_flag = 1; // تغییر پرچم
}</code></pre><p>در این مثال، اگر shared_flag به‌عنوان volatile تعریف نشود، کامپایلر ممکن است حلقه while را بهینه کند و تغییرات اعمال‌شده توسط نخ دوم را نادیده بگیرد.</p><h3>3. <strong>مدیریت وقفه‌ها (Interrupts)</strong></h3><p>در سیستم‌هایی که از وقفه‌های سخت‌افزاری استفاده می‌کنند، متغیرهایی که توسط روال‌های سرویس‌دهی وقفه (ISR) تغییر می‌کنند، باید volatile باشند. این کار تضمین می‌کند که تغییرات این متغیرها به درستی توسط برنامه اصلی دیده شوند. به مثال زیر توجه کنید:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>volatile int interrupt_flag = 0;

void ISR() {
    interrupt_flag = 1;
}

int main() {
    while (!interrupt_flag) {
        // منتظر وقفه
    }
    // ادامه پردازش
}</code></pre><p>بدون volatile، کامپایلر ممکن است فرض کند که interrupt_flag هرگز تغییر نمی‌کند و حلقه را به‌صورت بی‌نهایت اجرا کند.</p><h2>نکات مهم در استفاده از volatile</h2><p>استفاده از volatile نیازمند دقت است، زیرا استفاده نادرست از آن می‌تواند عملکرد برنامه را تحت تأثیر قرار دهد. در ادامه چند نکته کلیدی آورده شده است:</p><ul><li><p><strong>استفاده بیش از حد ممنوع</strong>: استفاده غیرضروری از volatile می‌تواند مانع بهینه‌سازی‌های مفید کامپایلر شود و عملکرد برنامه را کاهش دهد. تنها متغیرهایی که واقعاً ممکن است به‌صورت غیرمنتظره تغییر کنند را volatile کنید.</p></li><li><p><strong>ترکیب با سایر کلیدواژه‌ها</strong>: volatile می‌تواند با کلیدواژه‌هایی مانند const ترکیب شود. به عنوان مثال، volatile const int نشان‌دهنده متغیری است که نمی‌توان آن را در کد تغییر داد، اما ممکن است توسط عوامل خارجی (مثل سخت‌افزار) تغییر کند.</p></li><li><p><strong>محدودیت‌ها در چندنخی</strong>: volatile به‌تنهایی برای همگام‌سازی نخ‌ها کافی نیست. برای مدیریت دسترسی‌های همزمان، باید از ابزارهایی مانند قفل‌ها (locks) یا موانع حافظه (memory barriers) استفاده کنید.</p></li></ul><h2>تفاوت volatile با سایر مفاهیم مشابه</h2><p>برخی ممکن است volatile را با مفاهیمی مانند atomic یا مکانیزم‌های همگام‌سازی اشتباه بگیرند. volatile صرفاً به کامپایلر می‌گوید که بهینه‌سازی‌های خاصی را انجام ندهد، اما تضمین نمی‌کند که عملیات روی متغیر به‌صورت اتمیک (atomic) انجام شوند. برای عملیات اتمیک، باید از کتابخانه‌هایی مانند stdatomic.h در C11 استفاده کنید.</p><h2>مثال عملی: پیاده‌سازی یک پرچم وقفه</h2><p>برای درک بهتر، بیایید یک مثال عملی از استفاده volatile در یک سیستم نهفته ببینیم:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>#include &lt;stdio.h&gt;

volatile int sensor_data = 0;

void sensor_interrupt() {
    sensor_data++; // داده حسگر به‌روزرسانی می‌شود
}

int main() {
    while (1) {
        if (sensor_data &gt; 0) {
            printf("داده حسگر دریافت شد: %d\n", sensor_data);
            sensor_data = 0;
        }
    }
    return 0;
}</code></pre><p>در این کد، متغیر sensor_data توسط یک وقفه به‌روزرسانی می‌شود. اگر volatile استفاده نشود، ممکن است کامپایلر شرط if را بهینه کند و تغییرات sensor_data را نادیده بگیرد.</p><h2>چالش‌ها و محدودیت‌ها</h2><p>یکی از چالش‌های استفاده از volatile این است که درک دقیق زمان استفاده از آن نیازمند تجربه است. برنامه‌نویسان تازه‌کار ممکن است به‌اشتباه از آن استفاده کنند یا آن را نادیده بگیرند. همچنین، در برخی معماری‌های خاص، ممکن است نیاز به تنظیمات اضافی (مانند موانع حافظه) باشد تا رفتار مورد انتظار تضمین شود.</p><h2>چرا volatile کمتر شناخته‌شده است؟</h2><p>با وجود اهمیت volatile، این کلیدواژه در آموزش‌های ابتدایی C کمتر مورد توجه قرار می‌گیرد، زیرا کاربردهای آن بیشتر در زمینه‌های تخصصی مانند سیستم‌های نهفته یا برنامه‌نویسی بلادرنگ دیده می‌شود. در برنامه‌های ساده‌تر، که نیازی به تعامل با سخت‌افزار یا چندنخی نیست، این کلیدواژه کمتر به کار می‌رود. اما برای برنامه‌نویسان حرفه‌ای که با سیستم‌های پیچیده کار می‌کنند، volatile یکی از ابزارهای کلیدی است.</p><h2>نتیجه‌گیری</h2><p>کلیدواژه <strong>volatile</strong> در زبان C یکی از ابزارهای قدرتمند برای مدیریت متغیرهایی است که ممکن است به‌صورت غیرمنتظره تغییر کنند. این ویژگی در سناریوهایی مانند برنامه‌نویسی سخت‌افزار، سیستم‌های نهفته، و برنامه‌های چندنخی نقش حیاتی دارد. با درک صحیح و استفاده مناسب از volatile، می‌توانید از رفتار غیرمنتظره برنامه‌ها جلوگیری کنید و عملکرد قابل اعتمادی را تضمین کنید. اگر به برنامه‌نویسی سطح پایین علاقه‌مند هستید، یادگیری و تسلط بر این کلیدواژه می‌تواند شما را یک قدم به حرفه‌ای شدن نزدیک‌تر کند.</p><p>برای مطالعه بیشتر، پیشنهاد می‌کنم به استانداردهای زبان C (مانند C11) و مستندات کامپایلر خود (مثل GCC یا Clang) مراجعه کنید تا با جزئیات بیشتری از نحوه عملکرد volatile در پروژه‌های خود آشنا شوید.</p>]]></description><guid isPermaLink="false">25</guid><pubDate>Sat, 07 Jun 2025 17:42:00 +0000</pubDate></item><item><title>&#x645;&#x639;&#x631;&#x641;&#x6CC; &#x648;&#x6CC;&#x698;&#x6AF;&#x6CC; Readonly Classes &#x62F;&#x631; PHP 8.2</title><link>https://sinajalalvandi.ir/blog/programming/%D9%85%D8%B9%D8%B1%D9%81%DB%8C-%D9%88%DB%8C%DA%98%DA%AF%DB%8C-readonly-classes-%D8%AF%D8%B1-php-82-r24/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_05/readonly_classes_in_php_8_2_featured_image.webp.7a045e4790a4febc7b2d5012bc97175f.webp" /></p>
<p>در PHP 8.1، ویژگی <strong>Readonly Properties</strong> معرفی شد که به توسعه‌دهندگان اجازه می‌داد متغیرهای یک کلاس را به‌گونه‌ای تعریف کنند که فقط یک‌بار مقداردهی شوند و بعد از آن غیرقابل تغییر باشند. این قابلیت برای جلوگیری از تغییرات ناخواسته در متغیرها و افزایش ایمنی کد بسیار مفید بود. اما PHP 8.2 یک قدم فراتر رفت و مفهوم <strong>Readonly Classes</strong> را معرفی کرد. با این ویژگی، می‌توانید یک کلاس را به‌صورت کامل فقط خواندنی تعریف کنید، به این معنا که تمام متغیرهای (Properties) آن کلاس به‌صورت پیش‌فرض فقط خواندنی خواهند بود، بدون نیاز به تعریف جداگانه برای هر متغیر.</p><p>برای درک بهتر، بیایید یک مثال ساده را بررسی کنیم:</p><pre spellcheck="" class="ipsCode language-php" data-language="PHP"><code>readonly class UserProfile {
    public function __construct(
        public string $username,
        public string $email,
        public int $age
    ) {}
}</code></pre><p>در این کد، کل کلاس UserProfile به‌عنوان یک کلاس فقط خواندنی تعریف شده است. این یعنی متغیرهای username، email و age همگی به‌صورت خودکار فقط خواندنی هستند و نمی‌توان بعد از مقداردهی اولیه، آن‌ها را تغییر داد. اگر سعی کنید مقداری را تغییر دهید، مثلاً:</p><pre spellcheck="" class="ipsCode language-php" data-language="PHP"><code>$profile = new UserProfile('ali', 'ali@example.com', 30);
$profile-&gt;username = 'reza'; // خطا!</code></pre><p>مفسر PHP خطایی با این مضمون تولید می‌کند: "Cannot modify readonly property UserProfile::$username". این ویژگی تضمین می‌کند که داده‌های کلاس شما پس از ایجاد نمونه (Instantiation) تغییر نمی‌کنند و به این ترتیب، یک لایه امنیتی و پایداری به کد اضافه می‌شود.</p><h2>چرا Readonly Classes مهم است؟</h2><p>شاید با خودتان فکر کنید که این ویژگی خیلی هم جدید نیست و می‌توانستید با استفاده از Readonly Properties در PHP 8.1 به نتیجه مشابهی برسید. اما تفاوت اصلی در <strong>سادگی و خوانایی کد</strong> است. وقتی یک کلاس را به‌صورت readonly تعریف می‌کنید، دیگر نیازی نیست که برای هر متغیر کلمه کلیدی readonly را به‌صورت جداگانه بنویسید. این کار نه تنها کد را تمیزتر می‌کند، بلکه از خطاهای احتمالی ناشی از فراموش کردن افزودن readonly به یک متغیر جلوگیری می‌کند.</p><p>علاوه بر این، Readonly Classes به شما کمک می‌کند تا <strong>قصد طراحی</strong> (Design Intent) خود را به‌وضوح به سایر توسعه‌دهندگان نشان دهید. وقتی کلاسی را فقط خواندنی تعریف می‌کنید، به تیم خود (یا حتی خود آینده‌تان!) اعلام می‌کنید که این کلاس قرار است به‌عنوان یک موجودیت تغییرناپذیر (Immutable) عمل کند. این موضوع در پروژه‌های بزرگ که چندین توسعه‌دهنده روی کد کار می‌کنند، بسیار ارزشمند است.</p><h2>کاربردهای عملی Readonly Classes</h2><p>حالا بیایید به چند سناریوی واقعی نگاه کنیم که در آن‌ها Readonly Classes می‌تواند بدرخشد:</p><h3>1. مدل‌های داده‌ای (Data Models)</h3><p>یکی از رایج‌ترین کاربردهای Readonly Classes در تعریف مدل‌های داده‌ای است که قرار نیست پس از مقداردهی اولیه تغییر کنند. فرض کنید در حال توسعه یک سیستم مدیریت کاربران هستید. می‌توانید از یک کلاس فقط خواندنی برای ذخیره اطلاعات پروفایل کاربر استفاده کنید:</p><pre spellcheck="" class="ipsCode language-php" data-language="PHP"><code>readonly class User {
    public function __construct(
        public int $id,
        public string $name,
        public string $email
    ) {}
}</code></pre><p>این کلاس تضمین می‌کند که اطلاعات کاربر، مثل شناسه یا ایمیل، پس از ایجاد نمونه تغییر نمی‌کنند. این موضوع در برنامه‌هایی که نیاز به حفظ یکپارچگی داده‌ها دارند، مثل سیستم‌های مالی یا مدیریت هویت، بسیار مفید است.</p><h3>2. DTOها (Data Transfer Objects)</h3><p>Readonly Classes برای پیاده‌سازی اشیاء انتقال داده (DTO) بسیار مناسب هستند. DTOها معمولاً برای انتقال داده بین لایه‌های مختلف یک برنامه (مثلاً بین لایه‌های دیتابیس و API) استفاده می‌شوند. با استفاده از یک کلاس فقط خواندنی، می‌توانید مطمئن شوید که داده‌های منتقل‌شده در طول مسیر تغییر نمی‌کنند:</p><pre spellcheck="" class="ipsCode language-php" data-language="PHP"><code>readonly class OrderDTO {
    public function __construct(
        public int $orderId,
        public float $totalAmount,
        public string $status
    ) {}
}</code></pre><p>در اینجا، شیء OrderDTO به‌عنوان یک بسته داده‌ای عمل می‌کند که اطلاعات سفارش را بدون امکان تغییر منتقل می‌کند.</p><h3>3. افزایش امنیت در برنامه‌های وب</h3><p>یکی از چالش‌های رایج در توسعه وب، جلوگیری از تغییرات ناخواسته در داده‌ها به دلیل خطاهای برنامه‌نویسی یا حملات است. با استفاده از Readonly Classes، می‌توانید اطمینان حاصل کنید که داده‌های حساس، مثل تنظیمات پیکربندی یا اطلاعات کاربر، به‌صورت تصادفی یا مخرب تغییر نمی‌کنند.</p><h3>4. بهبود عملکرد در پروژه‌های بزرگ</h3><p>وقتی کلاسی به‌صورت فقط خواندنی تعریف می‌شود، مفسر PHP می‌تواند بهینه‌سازی‌های بیشتری روی آن اعمال کند، زیرا می‌داند که متغیرهای این کلاس تغییر نخواهند کرد. این موضوع در پروژه‌های بزرگ که عملکرد اهمیت زیادی دارد، می‌تواند تأثیر قابل‌توجهی داشته باشد.</p><h2>محدودیت‌ها و نکات قابل توجه</h2><p>هرچند Readonly Classes ویژگی قدرتمندی است، اما محدودیت‌هایی هم دارد که باید به آن‌ها توجه کنید:</p><ul><li><p><strong>عدم امکان تغییر پس از مقداردهی</strong>: وقتی کلاسی را فقط خواندنی تعریف می‌کنید، هیچ‌یک از متغیرهای آن قابل تغییر نیستند، حتی اگر در شرایط خاصی نیاز به تغییر داشته باشید. در چنین مواردی، باید از یک کلاس معمولی استفاده کنید یا منطق برنامه را بازطراحی کنید.</p></li><li><p><strong>محدودیت در ارث‌بری</strong>: اگر یک کلاس فقط خواندنی را به ارث ببرید، کلاس فرزند هم باید فقط خواندنی باشد. این موضوع می‌تواند در برخی طراحی‌های پیچیده محدودیت ایجاد کند.</p></li><li><p><strong>سازگاری با نسخه‌های قدیمی</strong>: این ویژگی فقط در PHP 8.2 و بالاتر در دسترس است. اگر پروژه شما نیاز به پشتیبانی از نسخه‌های قدیمی‌تر PHP دارد، باید راه‌حل‌های جایگزین (مثل Readonly Properties یا Getterها) را در نظر بگیرید.</p></li></ul><h2>چگونه از Readonly Classes استفاده کنیم؟</h2><p>برای استفاده از این ویژگی، کافی است کلمه کلیدی readonly را قبل از تعریف کلاس قرار دهید. همچنین، بهتر است متغیرهای عمومی (Public Properties) را در Constructor تعریف کنید تا مقداردهی اولیه به‌صورت شفاف انجام شود. مثال زیر یک نمونه کامل‌تر را نشان می‌دهد:</p><pre spellcheck="" class="ipsCode language-php" data-language="PHP"><code>readonly class Product {
    public function __construct(
        public string $name,
        public float $price,
        public int $stock
    ) {}

    public function getSummary(): string {
        return "Product: {$this-&gt;name}, Price: {$this-&gt;price}, Stock: {$this-&gt;stock}";
    }
}

$product = new Product('Laptop', 999.99, 10);
echo $product-&gt;getSummary(); // خروجی: Product: Laptop, Price: 999.99, Stock: 10</code></pre><p>در این مثال، کلاس Product نه تنها داده‌ها را به‌صورت فقط خواندنی نگه می‌دارد، بلکه با استفاده از متد getSummary، می‌توانید منطق نمایش داده‌ها را به‌راحتی پیاده‌سازی کنید.</p><h2>مقایسه با سایر زبان‌ها</h2><p>ویژگی‌هایی مثل Readonly Classes در زبان‌های دیگر هم وجود دارند. برای مثال، در جاوا می‌توانید از کلمه کلیدی final برای متغیرها یا کلاس‌ها استفاده کنید تا تغییرناپذیر شوند. در پایتون هم با استفاده از کتابخانه‌هایی مثل dataclasses و ویژگی frozen=True می‌توانید رفتار مشابهی را پیاده‌سازی کنید. اما آنچه PHP را متمایز می‌کند، سادگی و یکپارچگی این ویژگی با سینتکس موجود است که آن را برای توسعه‌دهندگان وب بسیار کاربردی می‌کند.</p><h2>نتیجه‌گیری</h2><p>ویژگی Readonly Classes در PHP 8.2 شاید در نگاه اول یک تغییر کوچک به نظر برسد، اما تأثیر آن در نوشتن کدهای تمیز، امن و قابل نگهداری قابل‌توجه است. این ویژگی به شما کمک می‌کند تا داده‌های تغییرناپذیر را به‌سادگی مدیریت کنید، از خطاهای ناخواسته جلوگیری کنید و قصد طراحی خود را به‌وضوح به سایر توسعه‌دهندگان منتقل کنید. اگر در حال کار روی یک پروژه جدید هستید یا قصد دارید پروژه موجودتان را به PHP 8.2 ارتقا دهید، حتماً این ویژگی را امتحان کنید. با کمی تمرین، متوجه خواهید شد که Readonly Classes می‌تواند به یکی از ابزارهای اصلی شما در توسعه وب تبدیل شود.</p>]]></description><guid isPermaLink="false">24</guid><pubDate>Thu, 29 May 2025 18:59:12 +0000</pubDate></item><item><title>&#x646;&#x6AF;&#x627;&#x647;&#x6CC; &#x628;&#x647; &#x645;&#x627;&#x6A9;&#x631;&#x648; &#x647;&#x627; &#x62F;&#x631; &#x632;&#x628;&#x627;&#x646; &#x628;&#x631;&#x646;&#x627;&#x645;&#x647;&#x200C;&#x646;&#x648;&#x6CC;&#x633;&#x6CC; Rust</title><link>https://sinajalalvandi.ir/blog/programming/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D9%87-%D9%85%D8%A7%DA%A9%D8%B1%D9%88-%D9%87%D8%A7-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C-rust-r23/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_05/rustmacro.webp.eb9ed6a72ad3b26faaf5fbd24213a4ee.webp" /></p>
<p>ماکروها (Macros) یکی از ویژگی‌های قدرتمند زبان Rust هستند که به شما امکان می‌دهند کدهایی بنویسید که کدهای دیگری تولید کنند. این ویژگی در مواردی مانند حذف کد تکراری، ایجاد DSLهای خاص‌منظوره، یا پیاده‌سازی metaprogramming patterns بسیار کاربردی است. در این مقاله با انواع ماکروها در Rust، مزایا، معایب و نحوه‌ی استفاده‌ی صحیح از آن‌ها آشنا می‌شویم.</p><p></p><h2>چرا ماکرو؟</h2><p>ماکروها زمانی به‌کار می‌آیند که کد شما دارای الگوهای تکراری زیادی باشد که با فانکشن‌ها به‌راحتی قابل بازنویسی نیستند. برخلاف توابع، ماکروها قبل از مرحله‌ی کامپایل اجرا می‌شوند و می‌توانند ساختارهای مختلفی از کد را تولید کنند. به‌عبارت دیگر، ماکروها به شما اجازه می‌دهند تا در مرحله‌ی کامپایل کد تولید کنید.</p><h2>انواع ماکروها در Rust</h2><p>Rust از دو نوع اصلی ماکرو پشتیبانی می‌کند:</p><h3>1. Declarative Macros (با استفاده از macro_rules!)</h3><p>این نوع ماکروها که با <code>macro_rules!</code> تعریف می‌شوند، از الگوهای تطبیقی برای تولید کد استفاده می‌کنند. این همان چیزی است که بیشتر توسعه‌دهندگان Rust در ابتدا با آن برخورد می‌کنند.</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>macro_rules! say_hello {
    () =&gt; {
        println!("Hello!");
    };
}

fn main() {
    say_hello!();
}</code></pre><p>ماکرو بالا هر بار که فراخوانی شود، کدی تولید می‌کند که <code>println!</code> را اجرا می‌کند. کاربرد آن بسیار شبیه توابع است، اما با این تفاوت که در مرحله‌ی pre-processing اجرا می‌شود.</p><p>از قابلیت‌های پیشرفته‌تر <code>macro_rules!</code> می‌توان به الگوهای چندگانه، تکرار با <code>*</code> و <code>+</code>، و پترن‌مچینگ اشاره کرد. مثلاً:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>macro_rules! create_functions {
    ($($name:ident),*) =&gt; {
        $(
            fn $name() {
                println!("You called {:?}!", stringify!($name));
            }
        )*
    }
}

create_functions!(foo, bar, baz);</code></pre><h3>2. Procedural Macros</h3><p>ماکروهای پردازشی نوع پیشرفته‌تری از ماکروها هستند که امکان اعمال تغییر روی AST (Abstract Syntax Tree) را فراهم می‌کنند. این ماکروها به سه دسته تقسیم می‌شوند:</p><h4>- #[derive]</h4><p>برای تولید کد به‌صورت خودکار روی ساختارها. مثلاً:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>#[derive(Debug, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}</code></pre><h4>- Attribute-like Macros</h4><p>ماکروهایی که با علامت <code>#[]</code> روی آیتم‌هایی مثل تابع یا ساختار اعمال می‌شوند:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>#[route(GET, "/")]
fn index() {}</code></pre><h4>- Function-like Macros</h4><p>شبیه به <code>macro_rules!</code> ولی با انعطاف بیشتر. مثلاً:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>my_macro!(...);</code></pre><p>این نوع ماکروها معمولاً در crate جداگانه‌ای نوشته می‌شوند و از <code>proc_macro</code> استفاده می‌کنند.</p><h2>نحوه‌ی نوشتن یک ماکرو Procedural ساده</h2><p>نوشتن ماکروهای procedural نیاز به استفاده از crate <code>proc-macro</code> دارد. به‌طور معمول، این کدها در crate جداگانه با نوع <code>proc-macro = true</code> تعریف می‌شوند.</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro]
pub fn make_answer(_item: TokenStream) -&gt; TokenStream {
    "fn answer() -&gt; u32 { 42 }".parse().unwrap()
}</code></pre><h2>مزایای استفاده از ماکروها</h2><ul><li><p><strong>کاهش کد تکراری:</strong> می‌توانید با چند خط ماکرو، صدها خط کد مشابه تولید کنید.</p></li><li><p><strong>افزایش خوانایی در برخی موارد:</strong> ماکروهای خوب طراحی‌شده می‌توانند کدی شفاف‌تر ارائه دهند.</p></li><li><p><strong>ایجاد DSL:</strong> ماکروها امکان ساخت syntax سفارشی را فراهم می‌کنند.</p></li></ul><h2>معایب ماکروها</h2><ul><li><p><strong>عیب‌یابی دشوار:</strong> خطاهای کامپایل در ماکروها ممکن است گنگ و پیچیده باشند.</p></li><li><p><strong>کاهش وضوح کد:</strong> اگر بیش‌ازحد از ماکرو استفاده شود، کد می‌تواند مبهم و غیرقابل‌خواندن شود.</p></li><li><p><strong>افزایش زمان کامپایل:</strong> چون ماکروها قبل از کامپایل اجرا می‌شوند، می‌توانند زمان build را افزایش دهند.</p></li></ul><h2>چه زمانی ماکرو ننویسیم؟</h2><p>اگر می‌توانید با یک تابع ساده یا generic مشکل را حل کنید، ماکرو ننویسید. ماکروها باید آخرین گزینه باشند، نه اولین. آن‌ها ابزاری قدرتمند ولی دو لبه‌اند: هم می‌توانند کدتان را زیباتر کنند، هم آن را به یک هیولای غیرقابل نگهداری تبدیل کنند.</p><h2>مثال کاربردی: DSL برای تست‌ها</h2><p>فرض کنید می‌خواهید یک DSL برای تست بنویسید:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>macro_rules! test_case {
    ($name:ident, $body:block) =&gt; {
        #[test]
        fn $name() $body
    };
}

test_case!(simple_addition, {
    assert_eq!(2 + 2, 4);
});</code></pre><h2>نتیجه‌گیری</h2><p>ماکروها در Rust ابزاری بسیار قدرتمند برای تولید کد هستند که با درک صحیح و استفاده‌ی هوشمندانه می‌توانند کدهای پیچیده را ساده کنند. اما باید با احتیاط از آن‌ها استفاده کرد، چرا که سوءاستفاده از آن‌ها منجر به ایجاد کدی می‌شود که نه تنها نگهداری آن سخت است، بلکه ممکن است شما را در کامپایل‌های نیم‌ساعته غرق کند.</p>]]></description><guid isPermaLink="false">23</guid><pubDate>Mon, 05 May 2025 17:56:04 +0000</pubDate></item><item><title>&#x647;&#x645;&#x647;&#x200C;&#x686;&#x6CC;&#x632; &#x62F;&#x631;&#x628;&#x627;&#x631;&#x647; &#x641;&#x627;&#x6CC;&#x644; Cargo.toml &#x62F;&#x631; Rust: &#x631;&#x627;&#x647;&#x646;&#x645;&#x627;&#x6CC; &#x62C;&#x627;&#x645;&#x639;</title><link>https://sinajalalvandi.ir/blog/programming/%D9%87%D9%85%D9%87%E2%80%8C%DA%86%DB%8C%D8%B2-%D8%AF%D8%B1%D8%A8%D8%A7%D8%B1%D9%87-%D9%81%D8%A7%DB%8C%D9%84-cargotoml-%D8%AF%D8%B1-rust-%D8%B1%D8%A7%D9%87%D9%86%D9%85%D8%A7%DB%8C-%D8%AC%D8%A7%D9%85%D8%B9-r22/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_04/cargo.avif.ffcd0032110017ef0f1eab22d882bfae.avif" /></p>
<p>در زبان برنامه‌نویسی Rust، ابزار <strong>Cargo</strong> نقش کلیدی در مدیریت پروژه‌ها ایفا می‌کند. این ابزار قدرتمند به توسعه‌دهندگان کمک می‌کند تا فرآیند ساخت، مدیریت وابستگی‌ها و انتشار پروژه‌ها را به‌سادگی انجام دهند. در مرکز هر پروژه‌ای که با Cargo مدیریت می‌شود، فایلی به نام Cargo.toml قرار دارد. این فایل، که به نوعی تنظیمات اصلی پروژه را در خود جای داده، مشخص می‌کند که پروژه چگونه باید ساخته شود، چه وابستگی‌هایی دارد و چه ویژگی‌هایی باید فعال شوند. در این مقاله، قصد داریم به‌صورت جامع و دقیق تمام جنبه‌های فایل Cargo.toml را بررسی کنیم تا بتوانید با تسلط بیشتری از آن در پروژه‌های خود استفاده کنید.</p><h4>فایل Cargo.toml چیست و چه اهمیتی دارد؟</h4><p>فایل Cargo.toml در واقع فایل پیکربندی اصلی پروژه‌های Rust است که با استفاده از ابزار Cargo مدیریت می‌شوند. این فایل در ریشه پروژه قرار می‌گیرد و اطلاعاتی مانند نام پروژه، نسخه، وابستگی‌ها و تنظیمات مختلف را در خود نگه می‌دارد. فرمت این فایل بر پایه <strong>TOML</strong> (مخفف Tom's Obvious, Minimal Language) است که یک زبان ساده و خوانا برای تعریف تنظیمات محسوب می‌شود.</p><p>هر زمان که دستوری مانند cargo build یا cargo run اجرا می‌کنید، Cargo ابتدا به سراغ این فایل می‌رود تا اطلاعات لازم را از آن بخواند. به همین دلیل، درک ساختار و قابلیت‌های این فایل برای هر توسعه‌دهنده Rust ضروری است.</p><h4>ساختار کلی فایل Cargo.toml</h4><p>یک فایل Cargo.toml ساده ممکن است به این شکل باشد:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[package]
name = "my_project"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = "1.0"</code></pre><p>در این مثال، دو بخش اصلی دیده می‌شود: بخش <strong>[package]</strong> که اطلاعات پایه پروژه را مشخص می‌کند و بخش <strong>[dependencies]</strong> که وابستگی‌های پروژه را تعریف می‌کند. اما این تنها بخش کوچکی از قابلیت‌های این فایل است. در ادامه، تمام بخش‌ها و فیلدهای ممکن را به‌صورت دقیق بررسی خواهیم کرد.</p><h3>بخش [package]: اطلاعات پایه پروژه</h3><p>بخش <strong>[package]</strong> شامل اطلاعات اصلی پروژه است که برای شناسایی و مدیریت آن استفاده می‌شود. فیلدهای مهم این بخش عبارت‌اند از:</p><ul><li><p><strong>name</strong>: نام پروژه را مشخص می‌کند. این نام باید منحصربه‌فرد باشد، به‌خصوص اگر قصد دارید پروژه را در <a rel="external nofollow" href="https://crates.io">crates.io</a> منتشر کنید (مثال: "my_project").</p></li><li><p><strong>version</strong>: نسخه پروژه، که معمولاً از فرمت Semantic Versioning پیروی می‌کند (مثال: "0.1.0").</p></li><li><p><strong>edition</strong>: نسخه ادیشن Rust که پروژه از آن استفاده می‌کند (مانند "2021", "2018" یا "2015"). این فیلد مشخص می‌کند که کد شما با کدام مجموعه از قوانین و ویژگی‌های Rust سازگار است.</p></li><li><p><strong>authors</strong>: فهرست نویسندگان پروژه (مثال: ["Sina Jalalvandi &lt;<a rel="" href="mailto:ali@example.com">sina@example.com</a>&gt;"]).</p></li><li><p><strong>description</strong>: توضیحی کوتاه درباره پروژه، که در صورت انتشار در <a rel="external nofollow" href="https://crates.io">crates.io</a> نمایش داده می‌شود.</p></li><li><p><strong>license</strong>: نوع مجوز پروژه (مانند "MIT" یا "Apache-2.0").</p></li><li><p><strong>repository</strong>: آدرس مخزن پروژه (مثلاً لینک گیت‌هاب).</p></li><li><p><strong>homepage</strong>: آدرس وب‌سایت پروژه (در صورت وجود).</p></li><li><p><strong>keywords</strong>: کلمات کلیدی مرتبط با پروژه برای جستجو در <a rel="external nofollow" href="https://crates.io">crates.io</a> (مثال: ["web", "rust", "api"]).</p></li><li><p><strong>categories</strong>: دسته‌بندی‌های پروژه (مثال: ["web-development", "data-structures"]).</p></li><li><p><strong>readme</strong>: مسیر فایل README پروژه (مثال: "<a rel="external nofollow" href="https://README.md">README.md</a>") که در زمان انتشار استفاده می‌شود.</p></li><li><p><strong>rust-version</strong>: حداقل نسخه Rust موردنیاز برای پروژه (مثال: "1.60")؛ این فیلد اختیاری است.</p></li></ul><p>یک نمونه کامل‌تر از بخش [package]:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[package]
name = "cool_app"
version = "0.2.0"
edition = "2021"
authors = ["Sara Ahmadi &lt;sara@example.com&gt;"]
description = "یه برنامه ساده برای تست Rust"
license = "MIT"
repository = "https://github.com/sara/cool_app"
homepage = "https://sara.example.com/cool_app"
keywords = ["rust", "test", "app"]
categories = ["development-tools"]
rust-version = "1.65"</code></pre><p></p><h3>بخش [dependencies]: تعریف وابستگی‌ها</h3><p>بخش <strong>[dependencies]</strong> برای مشخص کردن پکیج‌های خارجی (crates) موردنیاز پروژه استفاده می‌شود. می‌توانید نسخه دقیق یا بازه‌ای از نسخه‌ها را برای هر وابستگی تعیین کنید. چند روش رایج برای تعریف وابستگی‌ها:</p><ul><li><p><strong>نسخه ساده</strong>: مانند serde = "1.0" که نسخه 1.0 از crate موردنظر را مشخص می‌کند.</p></li><li><p><strong>بازه نسخه</strong>: مانند serde = "&gt;1.0, &lt;2.0" که هر نسخه‌ای بین 1.0 و 2.0 را شامل می‌شود.</p></li><li><p><strong>با ویژگی‌ها (features)</strong>: اگر crate موردنظر قابلیت‌های اختیاری داشته باشد، می‌توانید آن‌ها را فعال کنید:</p></li></ul><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[dependencies]
serde = { version = "1.0", features = ["derive"] }</code></pre><p><strong>مسیر محلی</strong>: اگر crate در سیستم شما باشد:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[dependencies]
my_local_crate = { path = "../my_local_crate" }</code></pre><p><strong>مخزن گیت</strong>: برای استفاده مستقیم از یک مخزن گیت:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[dependencies]
some_crate = { git = "https://github.com/user/some_crate" }</code></pre><h3>بخش [dev-dependencies]: وابستگی‌های توسعه</h3><p>این بخش برای وابستگی‌هایی است که فقط در مرحله توسعه و تست استفاده می‌شوند و در نسخه نهایی پروژه (هنگام اجرای cargo build --release) وارد نمی‌شوند. مثال:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[dev-dependencies]
assert_approx_eq = "1.1"</code></pre><h3>بخش [build-dependencies]: وابستگی‌های ساخت</h3><p>اگر پروژه شما از اسکریپت ساخت (build script) استفاده می‌کند، وابستگی‌های موردنیاز آن را می‌توانید در این بخش تعریف کنید:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[build-dependencies]
cc = "1.0"</code></pre><h3>بخش [features]: قابلیت‌های اختیاری</h3><p>بخش [features] به شما امکان می‌دهد قابلیت‌های اختیاری برای پروژه تعریف کنید که کاربران بتوانند آن‌ها را فعال یا غیرفعال کنند. مثال:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[features]
default = ["logging"]
logging = ["log"]
extra = []</code></pre><p>در این مثال، default مشخص می‌کند که ویژگی logging به‌صورت پیش‌فرض فعال باشد. ویژگی extra نیز تعریف شده اما فعلاً وابستگی‌ای ندارد.</p><h3>بخش [lib]: تنظیمات کتابخانه</h3><p>اگر پروژه شما یک کتابخانه (library) است، می‌توانید تنظیمات آن را در این بخش مشخص کنید:</p><ul><li><p><strong>name</strong>: نام کتابخانه (در صورتی که با نام پکیج متفاوت باشد).</p></li><li><p><strong>path</strong>: مسیر فایل اصلی کتابخانه (پیش‌فرض: src/<a rel="external nofollow" href="https://lib.rs">lib.rs</a>).</p></li><li><p><strong>crate-type</strong>: نوع خروجی کتابخانه (مانند "cdylib" برای کتابخانه‌های سازگار با C).</p></li></ul><p>مثال:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[lib]
name = "my_lib"
path = "src/my_lib.rs"
crate-type = ["rlib"]</code></pre><h3>بخش [[bin]]: تنظیمات فایل‌های اجرایی</h3><p>اگر پروژه شما شامل برنامه‌های اجرایی (binary) است، می‌توانید چندین فایل اجرایی را در این بخش تعریف کنید:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[[bin]]
name = "my_app"
path = "src/main.rs"

[[bin]]
name = "another_app"
path = "src/another.rs"</code></pre><h3>بخش [profile]: تنظیمات بهینه‌سازی</h3><p>این بخش برای تنظیم نحوه بهینه‌سازی پروژه در مراحل مختلف ساخت استفاده می‌شود. سه پروفایل اصلی وجود دارد:</p><ul><li><p><strong>[profile.dev]</strong>: برای مرحله توسعه (با دیباگ فعال).</p></li><li><p><strong>[profile.release]</strong>: برای نسخه نهایی (بهینه‌سازی بالا).</p></li><li><p><strong>[profile.test]</strong>: برای تست‌ها.</p></li></ul><p>مثال:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[profile.release]
opt-level = 3  # حداکثر بهینه‌سازی
debug = false</code></pre><h3>بخش [workspace]: مدیریت چند پروژه</h3><p>اگر چندین پروژه مرتبط دارید، می‌توانید آن‌ها را در یک Workspace مدیریت کنید:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[workspace]
members = ["crate1", "crate2"]</code></pre><p></p><h4>بخش [badges]: نمایش وضعیت پروژه</h4><p>بخش <strong>[badges]</strong> در فایل Cargo.toml به شما امکان می‌دهد وضعیت پروژه را به‌صورت بصری و با استفاده از برچسب‌های کوچک (badges) نمایش دهید. این برچسب‌ها معمولاً در صفحه پروژه در <a rel="external nofollow" href="https://crates.io">crates.io</a> یا در مستندات (مثلاً README گیت‌هاب) نشان داده می‌شوند و اطلاعاتی درباره وضعیت توسعه، تست‌ها یا کیفیت پروژه به کاربران ارائه می‌دهند. استفاده از بج‌ها می‌تواند پروژه شما را حرفه‌ای‌تر نشان دهد و اعتماد کاربران را جلب کند.</p><h4>بج‌های رایج</h4><p>در ادامه، چند نمونه از بج‌های رایجی که می‌توانید در این بخش تعریف کنید، آورده شده است:</p><ul><li><p><strong>maintenance</strong>: این بج وضعیت نگهداری پروژه را نشان می‌دهد. مقادیر ممکن برای آن عبارت‌اند از:</p><ul><li><p>"actively-developed": پروژه در حال توسعه فعال است.</p></li><li><p>"passively-maintained": پروژه به‌صورت غیرفعال نگهداری می‌شود.</p></li><li><p>"as-is": پروژه بدون تغییر ارائه شده است.</p></li><li><p>"experimental": پروژه آزمایشی است.</p></li><li><p>"deprecated": پروژه منسوخ شده است.</p></li></ul></li></ul><p>مثال:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[badges]
maintenance = { status = "actively-developed" }</code></pre><ul><li><p><strong>codecov</strong>: برای نمایش پوشش تست (code coverage) پروژه، اگر از سرویسی مثل Codecov استفاده می‌کنید.</p></li></ul><p>مثال:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>[badges]
codecov = { repository = "user/repo", branch = "main", service = "github" }</code></pre><p><strong>بج‌های دیگر</strong>: بج‌های دیگری مانند <strong>travis-ci</strong> (برای Travis CI)، <strong>circle-ci</strong> (برای CircleCI)، یا <strong>is-it-maintained-issue-resolution</strong> (برای نمایش میانگین زمان حل مسائل) نیز وجود دارند که بسته به نیاز پروژه می‌توانید از آن‌ها استفاده کنید.</p><h4>نکات مهم درباره بج‌ها</h4><ul><li><p><strong>محدودیت نمایش</strong>: همه بج‌ها در <a rel="external nofollow" href="https://crates.io">crates.io</a> نمایش داده نمی‌شوند. برای مثال، بج <strong>maintenance</strong> در <a rel="external nofollow" href="https://crates.io">crates.io</a> نشان داده می‌شود، اما بج‌های مربوط به <strong>CI/CD</strong> (مانند github-actions) بیشتر در README گیت‌هاب استفاده می‌شوند.</p></li><li><p><strong>تنظیمات اضافی</strong>: برای بج‌های مربوط به <strong>CI/CD</strong> یا پوشش تست، باید ابتدا سرویس مربوطه (مثلاً GitHub Actions یا Codecov) را در پروژه خود تنظیم کرده باشید.</p></li><li><p><strong>نمایش در README</strong>: برای نمایش بج‌ها در README، می‌توانید از لینک‌های مستقیم بج (مثلاً از <a rel="external nofollow" href="https://shields.io">shields.io</a> یا خود سرویس) استفاده کنید. به‌عنوان مثال:</p></li></ul><pre spellcheck="" class="ipsCode language-markdown" data-language="Markdown"><code>![CI](https://github.com/user/repo/actions/workflows/ci.yml/badge.svg)</code></pre><p>استفاده از بج‌ها نه‌تنها اطلاعات مفیدی به کاربران ارائه می‌دهد، بلکه نشان‌دهنده توجه شما به کیفیت و نگهداری پروژه است.</p><h3>نکات تکمیلی و کاربردی</h3><ul><li><p><strong>فایل Cargo.lock</strong>: این فایل همراه با Cargo.toml ایجاد می‌شود و نسخه دقیق وابستگی‌ها را قفل می‌کند. برای پروژه‌های اجرایی توصیه می‌شود آن را در گیت نگه دارید، اما برای کتابخانه‌ها معمولاً نیازی نیست.</p></li><li><p><strong>دستورات مفید</strong>: می‌توانید از cargo check برای بررسی سریع پروژه یا از cargo update برای به‌روزرسانی وابستگی‌ها استفاده کنید.</p></li><li><p><strong>فیلدهای سفارشی</strong>: امکان افزودن فیلدهای سفارشی با پیشوند metadata وجود دارد (مثال: <strong>[package.metadata.docs]</strong>).</p></li></ul><h3>حرف آخر</h3><p>فایل Cargo.toml یکی از مهم‌ترین اجزای هر پروژه Rust است که با ابزار Cargo مدیریت می‌شود. این فایل با ساختار ساده اما قدرتمند خود، امکان مدیریت پروژه، وابستگی‌ها و تنظیمات مختلف را فراهم می‌کند. در این مقاله، تمام بخش‌ها و قابلیت‌های این فایل را بررسی کردیم تا بتوانید با اطمینان بیشتری از آن در پروژه‌های خود استفاده کنید. اگر سؤال یا نکته‌ای در این زمینه دارید، خوشحال می‌شوم در بخش نظرات با شما در میان بگذارم.</p>]]></description><guid isPermaLink="false">22</guid><pubDate>Thu, 10 Apr 2025 12:42:00 +0000</pubDate></item><item><title>&#x627;&#x62A;&#x635;&#x627;&#x644; Rust &#x628;&#x647; C: &#x6CC;&#x647; &#x631;&#x627;&#x647;&#x646;&#x645;&#x627;&#x6CC; &#x6A9;&#x627;&#x631;&#x628;&#x631;&#x62F;&#x6CC; &#x628;&#x631;&#x627;&#x6CC; &#x628;&#x631;&#x646;&#x627;&#x645;&#x647;&#x200C;&#x646;&#x648;&#x6CC;&#x633;&#x200C;&#x647;&#x627;</title><link>https://sinajalalvandi.ir/blog/programming/%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-rust-%D8%A8%D9%87-c-%DB%8C%D9%87-%D8%B1%D8%A7%D9%87%D9%86%D9%85%D8%A7%DB%8C-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF%DB%8C-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%E2%80%8C%D9%87%D8%A7-r18/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_03/rust-ffi-c.png.d1e6afd8f57fd68e8fc2b9a9712dbf74.png" /></p>
<p>اگه برنامه‌نویس باشی و با Rust کار کرده باشی، حتما شنیدی که این زبان چقدر رو سرعت و امنیت تمرکز داره. از اون طرف، C هم که یه زبان قدیمی و قدرتمنده و هنوز توی خیلی از پروژه‌ها، مخصوصا پروژه‌های سیستمی، حرف اول رو می‌زنه. حالا فکر کن بخوای این دو تا رو با هم ترکیب کنی! هم قدرت و انعطاف C رو داشته باشی، هم ایمنی و مدرن بودن Rust رو. توی این مطلب می‌خوام بهت نشون بدم چطور می‌تونی Rust و C رو به هم وصل کنی و کدات رو بین این دو تا جابجا کنی.</p><h4>چرا اصلا Rust و C رو به هم وصل کنیم؟</h4><p>قبل از اینکه بریم سراغ کد و جزییات، بذار یه لحظه ببینیم چرا این کار منطقیه. Rust یه زبان نسبتا جدیده که خیلی از مشکلات C مثل مدیریت دستی حافظه و خطاهای اشاره‌گر (pointer errors) رو حل کرده. اما خب، C یه اکوسیستم عظیم داره؛ کتابخونه‌هایی مثل POSIX یا حتی کدهای قدیمی پروژه‌ات که نمی‌خوای از صفر با Rust بازنویسی‌شون کنی. اینجا اتصال این دو زبان به کار میاد. می‌تونی از کتابخونه‌های C توی Rust استفاده کنی یا برعکس، کدهای Rust رو توی پروژه‌های C وارد کنی.</p><h4>مفاهیم اولیه: FFI چیه؟</h4><p>برای اینکه Rust و C با هم حرف بزنن، از یه چیزی به اسم FFI استفاده می‌کنیم. FFI مخفف "Foreign Function Interface" هست و به زبون ساده، یه جور پل ارتباطی بین زبون‌های مختلفه. توی این مورد، FFI به Rust اجازه می‌ده توابع C رو فراخوانی کنه و برعکس. اما این کار یه سری اصول داره که باید رعایت کنی، چون Rust و C توی مدیریت حافظه و ساختار داده‌ها خیلی فرق دارن.</p><h4>قدم اول: یه تابع C بنویس</h4><p>بیا با یه مثال ساده شروع کنیم. فرض کن توی C یه تابع داری که دو تا عدد رو می‌گیره و جمع‌شون می‌کنه:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>// math.c
int add(int a, int b) {
    return a + b;
}</code></pre><p>برای اینکه Rust بتونه این تابع رو ببینه، باید یه فایل هدر (header) هم بسازی:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>// math.h
#ifndef MATH_H
#define MATH_H

int add(int a, int b);

#endif</code></pre><p>حالا این فایل C رو کامپایل می‌کنیم تا یه کتابخونه استاتیک بسازیم:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="‏متن ساده ‏"><code>gcc -c math.c -o math.o
ar rcs libmath.a math.o</code></pre><p>تا اینجا یه کتابخونه به اسم libmath.a داریم که قراره توی Rust ازش استفاده کنیم.</p><h4>قدم دوم: اتصال به Rust</h4><p>توی پروژه Rust، باید به کامپایلر بگی که این کتابخونه خارجی رو لینک کنه. برای این کار از build.rs استفاده می‌کنیم. اگه پروژه‌ات هنوز فایل build.rs نداره، توی ریشه پروژه یه فایل با این اسم بساز و این کد رو توش بذار:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>// build.rs
fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rustc-link-lib=math");
    println!("cargo:rustc-link-search=native=.");
}</code></pre><p>این کد به Rust می‌گه که کتابخونه libmath.a رو پیدا کنه و به پروژه لینک کنه. یادت باشه فایل libmath.a رو توی همون دایرکتوری پروژه‌ات کپی کنی.</p><h4>قدم سوم: تعریف تابع در Rust</h4><p>حالا باید به Rust بگیم که تابع add توی C چه شکلیه. این کار رو با استفاده از بلاک extern "C" انجام می‌دیم. توی فایل main.rs اینجوری می‌نویسی:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>// main.rs
extern "C" {
    fn add(a: i32, b: i32) -&gt; i32;
}

fn main() {
    unsafe {
        let result = add(5, 3);
        println!("Result: {}", result);
    }
}</code></pre><p>ری می‌کنه که مسئولیت هر مشکلی گردن خودته!</p><h4>اجرا و تست</h4><p>حالا کافیه پروژه رو با cargo run اجرا کنی. اگه همه چیز درست پیش بره، خروجی باید این باشه:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="‏متن ساده ‏"><code>Result: 8</code></pre><p>تبریک! تونستی یه تابع C رو توی Rust فراخوانی کنی.</p><h4>برعکسش چطوره؟ Rust به C</h4><p>حالا فرض کن بخوای یه تابع توی Rust بنویسی و توی C ازش استفاده کنی. بیایم یه مثال بزنیم. توی Rust یه تابع می‌سازیم که یه رشته رو می‌گیره و طولش رو برمی‌گردونه:</p><pre spellcheck="" class="ipsCode language-rust" data-language="Rust"><code>// lib.rs
#[no_mangle]
pub extern "C" fn string_length(s: *const i8) -&gt; i32 {
    unsafe {
        let c_str = std::ffi::CStr::from_ptr(s);
        c_str.to_bytes().len() as i32
    }
}</code></pre><p><code>#[no_mangle]</code>به Rust می‌گه اسم تابع رو تغییر نده تا C بتونه پیداش کنه. حالا این پروژه رو به صورت کتابخونه کامپایل می‌کنیم:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="‏متن ساده ‏"><code>cargo build --release</code></pre><p>فایل librust.a توی پوشه target/release ساخته می‌شه.</p><p>توی C اینجوری ازش استفاده می‌کنیم:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>// main.c
#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;

extern int32_t string_length(const char* s);

int main() {
    const char* text = "Hello from Rust!";
    int32_t len = string_length(text);
    printf("Length: %d\n", len);
    return 0;
}</code></pre><p>کامپایلش می‌کنیم:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="‏متن ساده ‏"><code>gcc -L ./target/release -lrust main.c -o test</code></pre><p>اگه اجرا کنی، خروجی می‌شه:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="‏متن ساده ‏"><code>Length: 16</code></pre><h4>نکات مهم و چالش‌ها</h4><p>اتصال Rust و C خیلی هم ساده نیست. باید حواست به مدیریت حافظه باشه؛ مثلا اگه توی C حافظه تخصیص دادی، Rust انتظار نداره خودش آزادش کنه. یا برعکس، اگه Rust یه چیزی رو آزاد کرد، C نباید دوباره بخواد باهاش کار کنه. یه ابزار خوب برای این کار، استفاده از کتابخونه‌هایی مثل cbindgen و bindgen هست که فایل‌های هدر و تعاریف رو خودکار تولید می‌کنن و کار رو راحت‌تر می‌کنن.</p><h4>جمع‌بندی</h4><p>وصل کردن Rust به C یه راه عالیه برای اینکه از بهترین‌های هر دو دنیا استفاده کنی. با FFI و چند خط کد، می‌تونی پروژه‌هات رو قوی‌تر و انعطاف‌پذیرتر کنی.</p>]]></description><guid isPermaLink="false">18</guid><pubDate>Fri, 21 Mar 2025 13:45:42 +0000</pubDate></item><item><title>&#x628;&#x631;&#x646;&#x627;&#x645;&#x647;&#x200C;&#x646;&#x648;&#x6CC;&#x633;&#x6CC; &#x645;&#x62A;&#x627; &#x62F;&#x631; C &#x628;&#x627; &#x645;&#x627;&#x6A9;&#x631;&#x648;&#x647;&#x627; &#x648; &#x67E;&#x6CC;&#x634;&#x200C;&#x67E;&#x631;&#x62F;&#x627;&#x632;&#x646;&#x62F;&#x647;</title><link>https://sinajalalvandi.ir/blog/programming/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D9%85%D8%AA%D8%A7-%D8%AF%D8%B1-c-%D8%A8%D8%A7-%D9%85%D8%A7%DA%A9%D8%B1%D9%88%D9%87%D8%A7-%D9%88-%D9%BE%DB%8C%D8%B4%E2%80%8C%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D9%86%D8%AF%D9%87-r16/</link><description><![CDATA[
<p><img src="https://sinajalalvandi.ir/uploads/monthly_2025_03/cdYTRZi.jpeg.45b64f2706740ff10441c1f689366b40.jpeg" /></p>
<p>زبان C به دلیل سادگی، کارایی بالا و دسترسی مستقیم به سخت‌افزار، یکی از پرکاربردترین زبان‌های برنامه‌نویسی است. اما یکی از قابلیت‌های قدرتمند و در عین حال کمتر شناخته‌شده آن، <strong>برنامه‌نویسی متا</strong> با استفاده از ماکروها و پیش‌پردازنده است. این قابلیت به شما امکان می‌دهد کدهایی انعطاف‌پذیر، بهینه و خودکار تولید کنید که در زمان کامپایل پردازش شده و از نظر کارایی بسیار سریع هستند.</p><h2>پیش‌پردازنده C چیست؟</h2><p>پیش‌پردازنده C یک مرحله قبل از کامپایل است که در آن دستورات خاصی پردازش شده و کد نهایی قبل از کامپایل تولید می‌شود. این مرحله شامل:</p><ul><li><p><strong>تعریف ماکروها (</strong><code>#define</code><strong>)</strong></p></li><li><p><strong>شرطی‌سازی کامپایل (</strong><code>#ifdef</code><strong>، </strong><code>#ifndef</code><strong>)</strong></p></li><li><p><strong>گنجاندن فایل‌ها (</strong><code>#include</code><strong>)</strong></p></li><li><p><strong>دستورات پیش‌پردازنده‌ی دیگر مانند </strong><code>#pragma</code><strong> و </strong><code>#error</code></p></li></ul><p>ماکروها، که معمولاً با <code>#define</code> تعریف می‌شوند، پایه اصلی برنامه‌نویسی متا در C هستند.</p><h2>برنامه‌نویسی متا با ماکروها</h2><p>برنامه‌نویسی متا در C عمدتاً به کمک <strong>ماکروها</strong> و <strong>توابع درون‌خطی</strong> انجام می‌شود. در ادامه چند نمونه از استفاده‌های پیشرفته ماکروها را بررسی می‌کنیم.</p><h3>1. ماکروهای توابع (Function-like Macros)</h3><p>ماکروها می‌توانند مانند توابع رفتار کنند اما بدون سربار فراخوانی تابع، زیرا مستقیماً در کد جایگذاری می‌شوند.</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>#include &lt;stdio.h&gt;

#define SQUARE(x) ((x) * (x))

int main() {
    int num = 5;
    printf("Square of %d is %d\n", num, SQUARE(num));
    return 0;
}
</code></pre><p>در اینجا <code>SQUARE(5)</code> به <code>((5) * (5))</code> تبدیل شده و مقدار 25 چاپ می‌شود. این نوع ماکروها برای بهینه‌سازی محاسبات ساده بسیار مفید هستند.</p><h3>2. استفاده از <code>#</code> و <code>##</code> در ماکروها</h3><p>دو عملگر خاص در ماکروهای C وجود دارند:</p><ul><li><p><code>#</code> برای تبدیل آرگومان به رشته</p></li><li><p><code>##</code> برای چسباندن دو آرگومان به هم</p></li></ul><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>#include &lt;stdio.h&gt;

#define TO_STRING(x) #x
#define CONCAT(a, b) a##b

int main() {
    printf("String: %s\n", TO_STRING(Hello, World!));
    
    int xy = 100;
    printf("Concatenated Variable: %d\n", CONCAT(x, y));
    return 0;
}
</code></pre><p>در این مثال:</p><ul><li><p><code>TO_STRING(Hello, World!)</code> مقدار <code>"Hello, World!"</code> را تولید می‌کند.</p></li><li><p><code>CONCAT(x, y)</code> باعث می‌شود <code>xy</code> به عنوان متغیر خوانده شود و مقدار 100 را نمایش دهد.</p></li></ul><h3>3. ماکروهای متغیر (Variadic Macros)</h3><p>ماکروهای متغیر می‌توانند تعداد نامحدودی آرگومان دریافت کنند.</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>#include &lt;stdio.h&gt;

#define DEBUG_PRINT(fmt, ...) printf("DEBUG: " fmt "\n", __VA_ARGS__)

int main() {
    DEBUG_PRINT("Value of x: %d", 10);
    DEBUG_PRINT("Sum: %d, Product: %d", 5 + 3, 5 * 3);
    return 0;
}
</code></pre><p>در اینجا <code>__VA_ARGS__</code> آرگومان‌های متغیر را پردازش کرده و امکان لاگ‌گیری انعطاف‌پذیر را فراهم می‌کند.</p><h2>مزایا و معایب برنامه‌نویسی متا در C</h2><h3>مزایا</h3><p> <strong>بهینه‌سازی سرعت</strong> – ماکروها مستقیماً در کد جایگزین می‌شوند و باعث حذف سربار اجرای تابع می‌شوند.<br> <strong>کاهش تکرار کد</strong> – بسیاری از کدهای تکراری را می‌توان به ماکرو تبدیل کرد.<br> <strong>امکان برنامه‌نویسی سطح پایین</strong> – امکان تعریف ساختارهای پیشرفته مانند مدیریت سخت‌افزار و رجیسترهای پردازنده را فراهم می‌کند.</p><h3>معایب</h3><p><strong>دیباگ دشوار</strong> – خطاهای ناشی از ماکروها معمولاً در خروجی کامپایل ظاهر نمی‌شوند و تشخیص مشکل سخت است.<br><strong>عدم بررسی نوع داده</strong> – ماکروها مانند توابع تایپ‌سیف نیستند و ممکن است مشکلاتی در نوع داده ایجاد کنند.<br><strong>افزایش پیچیدگی کد</strong> – خوانایی کد در صورت استفاده نادرست از ماکروها کاهش می‌یابد.</p><h2>نمونه‌های کاربردی برنامه‌نویسی متا در C</h2><h3>1. مدیریت حافظه هوشمند</h3><p>یکی از کاربردهای متا، تعریف ماکروهایی برای تخصیص و آزادسازی خودکار حافظه است.</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#define SAFE_ALLOC(ptr, size) do { ptr = malloc(size); if (!ptr) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } } while(0)

int main() {
    int *arr;
    SAFE_ALLOC(arr, 10 * sizeof(int));
    
    // استفاده از آرایه...
    
    free(arr);
    return 0;
}
</code></pre><p>این ماکرو اطمینان حاصل می‌کند که تخصیص حافظه موفق بوده و در غیر این صورت برنامه را متوقف می‌کند.</p><h3>2. تبدیل توابع به درون‌خطی (Inline Functions)</h3><p>اگرچه <code>inline</code> در C مدرن موجود است، اما در نسخه‌های قدیمی‌تر C، ماکروها برای درون‌خطی کردن توابع استفاده می‌شدند:</p><pre spellcheck="" class="ipsCode language-c" data-language="C"><code>#define MAX(a, b) ((a) &gt; (b) ? (a) : (b))

int main() {
    printf("Max: %d\n", MAX(10, 20));
    return 0;
}
</code></pre><h2>در نهایت</h2><p>برنامه‌نویسی متا در C با استفاده از ماکروها و پیش‌پردازنده یک ابزار قدرتمند برای بهینه‌سازی، کاهش تکرار کد و خودکارسازی عملیات پیچیده است. این تکنیک به‌ویژه در سیستم‌های نهفته، توسعه کرنل و برنامه‌های کارایی‌محور بسیار پرکاربرد است. با این حال، نیاز به درک عمیق از ساختار کد و مدیریت صحیح خطاها دارد تا از مشکلات رایج آن جلوگیری شود.</p><p>استفاده مناسب از ماکروها می‌تواند توسعه نرم‌افزار را سریع‌تر، بهینه‌تر و خواناتر کند، اما باید از استفاده بیش‌ازحد و غیرضروری آن‌ها اجتناب کرد.</p><p></p>]]></description><guid isPermaLink="false">16</guid><pubDate>Wed, 15 Jan 2025 03:37:00 +0000</pubDate></item></channel></rss>
