أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
البرمجة بالعربي

Borrow Checker في Rust للمبتدئ: ليه الكومبايلر بيرفض كودك

📅 ٢٥ مايو ٢٠٢٦⏱ 8 دقائق قراءة
Borrow Checker في Rust للمبتدئ: ليه الكومبايلر بيرفض كودك

المستوى المطلوب: مبتدئ — هذا المقال موجّه للمطورين اللي بيبدأوا في Rust لأول مرة أو سمعوا عنها بس عمرهم ما فهموا ليه الكومبايلر بيتعب معاهم. مش محتاج خبرة سابقة في Rust، بس محتاج تكون كاتبت كود قبل كده في أي لغة (JavaScript، Python، Java، أو حتى C).

لو شغّلت أول مشروع Rust ولقيت الـ Compiler بيرجّعلك خطأ cannot borrow `x` as mutable more than once at a time، انت مش بتعمل حاجة غلط. انت بتقابل النظام اللي بيخلّي Rust أسرع من Go وأأمن من C في نفس الوقت: الـ Borrow Checker.

Borrow Checker في Rust: المفتاح اللي بيخلّي اللغة آمنة بدون GC

الـ Borrow Checker مش عقبة في طريقك، هو الميزة الأساسية في Rust. هيمنعك من 70% من bugs الذاكرة قبل ما الكود يشتغل، حسب تقرير Microsoft Security Response Center سنة 2019 على CVEs ربع قرن في منتجات الشركة.

شاشة محرر كود مفتوحة على ملف Rust بلون داكن مع أسطر تظهر تعريف دالة واستخدام references

المشكلة باختصار: ليه اللغات الموجودة مش كفاية

قبل ما نفهم Rust، لازم نفهم المشكلة اللي بيحلها. فيه 3 طرق شائعة لإدارة الذاكرة، وكل واحدة فيها مشكلة:

  • إدارة يدوية (C و C++): انت اللي بتعمل malloc و free يدوي. ميزة: أسرع أداء ممكن. عيب: bug واحد في الإدارة (use-after-free، double-free، buffer overflow) ممكن يكلّفك ثغرة أمنية في الإنتاج.
  • Garbage Collector (Java، Python، Go): الـ runtime بيمسح الذاكرة تلقائياً. ميزة: ما بتفكّرش فيها. عيب: pauses عشوائية (Go GC pause بين 100µs و 1ms على heap كبير)، واستهلاك RAM أعلى بـ 2× إلى 3× من اللازم.
  • Reference Counting (Swift، Python): كل قيمة بتعدّ كام reference بتشير لها. ميزة: deterministic. عيب: مش بيحل cycles بدون weak references يدوية.

Rust جابت طريق رابع جديد: الـ Compiler يفحص قواعد الـ Ownership وقت الـ build، وبيرفض أي كود ممكن يعمل مشكلة ذاكرة. النتيجة zero-cost abstraction حقيقية: مفيش GC، مفيش runtime overhead، مفيش pauses.

المفهوم بمثال يومي: مفتاح الشقة

قبل ما ندخل في التعريف العلمي، خد المثال ده ببساطة شديدة. تخيّل إنك ساكن في شقة وعندك مفتاح واحد بس لها:

  • المالك واحد فقط: المفتاح في إيد شخص واحد في كل لحظة. مينفعش انت وأخوك تكونوا ماسكين نفس المفتاح في نفس الثانية.
  • الاستعارة (Borrow): لو صاحبك عايز يدخل الشقة، انت بتديله المفتاح يستعيره. لما يخلّص، المفتاح يرجع لك. هو ما اشتراش الشقة، هو بس استعار المفتاح.
  • قاعدة الاستعارة الذهبية: لو حد ماسك المفتاح علشان يغيّر القفل (mutable)، مينفعش حد تاني ياخد المفتاح في نفس الوقت. أما لو هو بس بيتفرّج على الشقة (immutable)، يقدر يكون فيه 100 ناس ماخدين نسخة من نفس المفتاح في نفس الوقت — ما داموا كلهم بيتفرّجوا بس.

دي بالظبط القواعد الـ3 الأساسية في Rust:

  1. كل قيمة ليها مالك واحد فقط (Owner).
  2. لما المالك يخرج من نطاقه (scope)، القيمة تتمسح من الذاكرة تلقائياً.
  3. في أي وقت، إما reference واحدة mutable، أو عدد لا نهائي من references immutable — مينفعش الاتنين مع بعض.

التعريف العلمي الدقيق

الـ Borrow Checker هو جزء من Rust Compiler بيـ implement نظام اسمه "Affine Type System" مبني على أبحاث في linear logic بدأت في الثمانينات (Jean-Yves Girard، 1987). المرجع الرسمي الأساسي هو فصل "What is Ownership?" في كتاب The Rust Programming Language، و RFC 2025 (Nested Method Calls) اللي اتضافت في Rust 2018 edition.

بشكل تقني: كل قيمة في Rust ليها lifetime — فترة زمنية بتعيشها في الذاكرة من ساعة ما اتعمل لها allocate لحد ساعة ما المالك يخرج من scope. الـ Compiler بيتتبع lifetimes كل reference، ويتأكد إن مفيش reference بتشير لذاكرة اتحرّرت (dangling reference)، ومفيش mutable reference بيتشاركها أكتر من thread (data race).

الافتراض هنا إن كل ده بيحصل وقت الـ compile time. يعني لو الكود اتجمّع بدون أخطاء، انت بتاخد ضمانة رياضية إن مفيش memory safety bugs في الـ binary بتاعك (إلا لو استخدمت unsafe صراحة).

مثال كود شغّال على rustc 1.83

الكود ده بيشتغل تمام:

Rust
fn main() {
    let mut name = String::from("أحمد");

    let r1 = &name;          // immutable borrow
    let r2 = &name;          // immutable borrow تاني، مفيش مشكلة
    println!("{} و {}", r1, r2);
    // r1 و r2 خلصوا استخدامهم هنا (Non-Lexical Lifetimes)

    let r3 = &mut name;      // mutable borrow، مسموح دلوقتي
    r3.push_str(" حايس");
    println!("{}", r3);
}

ليه الكود ده شغّال؟ لأن استخدام r1 و r2 خلص بعد println! الأول، فالـ Compiler عرف إن الـ immutable borrows مفعّلة لحد السطر ده بس. بعدها قدرنا ناخد mutable borrow في r3 لأن مفيش حد تاني ماسك name دلوقتي.

دلوقتي شوف الكود اللي بيفشل:

Rust
fn main() {
    let mut name = String::from("أحمد");

    let r1 = &name;
    let r2 = &mut name;     // ❌ هنا الكومبايلر هيرفض

    println!("{} و {}", r1, r2);
}

الكومبايلر هيرجّعلك:

error[E0502]: cannot borrow `name` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:14
  |
4 |     let r1 = &name;
  |              ----- immutable borrow occurs here
5 |     let r2 = &mut name;
  |              ^^^^^^^^^ mutable borrow occurs here
6 |
7 |     println!("{} و {}", r1, r2);
  |                         -- immutable borrow later used here

الكومبايلر منعك تعمل bug ممكن في C يخلّي القارئ يشوف نص قديم ونص جديد في نفس اللحظة لو حصل context switch بين الـ threads.

رقاقات ذاكرة RAM متراصة على لوحة أم تمثل إدارة الذاكرة في الكمبيوتر

أرقام مقاسة: Rust vs Go في الإنتاج

على benchmark من TechEmpower Round 22 (يناير 2024) لـ HTTP framework خفيف بـ JSON serialization:

  • Rust (Actix Web 4): 1,247,000 req/sec، استهلاك RAM 38MB، latency P99 = 1.2ms.
  • Go (Gin 1.10): 412,000 req/sec، استهلاك RAM 187MB، latency P99 = 4.7ms بسبب GC pauses.
  • Node.js (Fastify 4): 184,000 req/sec، استهلاك RAM 142MB، latency P99 = 8.3ms.

الفرق الـ 3× في الـ throughput مش في تصميم اللغة بس، هو في إن Rust مفيهاش runtime ولا garbage collector. الـ Borrow Checker هو اللي بيدفع تكلفة ده وقت الـ compile.

الـ Trade-offs الحقيقية اللي محدّش بيقولك عليها

  1. منحنى تعلّم حاد جداً: أول 2-3 أسابيع من Rust بيكون مرهق نفسياً. غالبية المطورين بيحسوا إن اللغة بتعاديهم شخصياً. حسب Stack Overflow Developer Survey 2024، Rust هي most loved language للسنة التامنة على التوالي، لكن most loved بيجي بعد فترة معاناة حقيقية.
  2. وقت compile أطول 3× إلى 10×: Rust compile time أبطأ من Go بفارق كبير على نفس حجم الكود. مشروع متوسط (50K سطر) ممكن ياخد دقيقة كاملة في clean build. الـ incremental builds أسرع، بس لسه أبطأ من Go.
  3. كود أطول قليلاً: التعامل مع lifetimes و references صراحة بيخلّي بعض الـ patterns تحتاج كود إضافي. عشان كده Rust أطول من Go بـ 15-20% في المتوسط لنفس feature.
  4. صعوبة في data structures معقّدة: linked lists و graphs و trees بـ shared mutable nodes صعبة في Rust بدون استخدام Rc<RefCell<T>>، اللي بيشيل ضمانات الـ Borrow Checker وقت الـ compile وبيحوّلها لـ panics وقت الـ runtime.

متى لا تستخدم Rust

Rust ليست الخيار الصحيح في الحالات دي، وكويس تعرفها قبل ما تختار:

  • MVP أو startup في أول 6 شهور: سرعة التطوير أهم بكتير من الأداء. استخدم Python أو TypeScript وانت بتدوّر على product-market fit.
  • scripting قصير: لو محتاج script يقرا CSV ويبعت email، Rust مبالغة هندسية. Python كافي وأسرع في الكتابة.
  • web frontend: فيه Yew و Leptos و Dioxus، لكن النظام البيئي لسه ضعيف مقارنة بـ React أو Vue.
  • data science و ML: النظام البيئي لـ Python (pandas، numpy، PyTorch، scikit-learn) لسه متقدّم بفارق سنين.
  • فريق بدون خبرة في systems programming: لو الفريق كله junior و backend اشتغلوا Node.js بس، الانتقال لـ Rust هياخد 3-6 شهور قبل ما الإنتاجية ترجع لمستواها.

الخطوة التالية

افتح الـ terminal وكتب cargo new rust-borrow-demo، وحاول تعيد كتابة الكود اللي فوق وتغيّر فيه عشان تشوف الكومبايلر بيقول إيه. لو ظهرلك خطأ، اقرا رسالة الكومبايلر بالكامل — Rust أحسن compiler في العالم في رسائل الأخطاء، وهو بيقولك بالظبط الـ borrow حصل فين والـ conflict مع إيه. لو لقيت نفسك بتقاوم الـ Borrow Checker بإنك تكتب .clone() في كل سطر، انت بتكتب Java في صياغة Rust؛ ارجع للقواعد الـ3 فوق وفكّر تاني مين المالك الحقيقي للقيمة.

المصادر

  • The Rust Programming Language Book — فصل "What is Ownership?": doc.rust-lang.org/book/ch04-01-what-is-ownership.html
  • RFC 2025 — Nested Method Calls (Rust 2018 edition): github.com/rust-lang/rfcs/blob/master/text/2025-nested-method-calls.md
  • Microsoft Security Response Center — "We Need a Safer Systems Programming Language" (يوليو 2019): msrc.microsoft.com/blog/2019/07/we-need-a-safer-systems-programming-language
  • TechEmpower Web Framework Benchmarks، Round 22 (يناير 2024): techempower.com/benchmarks
  • Stack Overflow Developer Survey 2024 — Most Loved Languages: survey.stackoverflow.co/2024/technology
  • rustc 1.83 Release Notes (نوفمبر 2024): blog.rust-lang.org/2024/11/28/Rust-1.83.0.html
  • Jean-Yves Girard — "Linear Logic" (Theoretical Computer Science، 1987) — الأساس النظري للـ Affine Type System

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة