لماذا يكسر Rust القواعد (وهذا طبيعي)
\n\nRust هي لغة التحدي. لا تغفر الكسل، ولا تتهاون في "هذا يكفي"، وتتطلب من المبرمج فهمًا عميقًا للذاكرة. لهذا السبب، يعاني العديد من المطورين، خاصة بعد Python أو JavaScript، من صدمة ثقافية. هل اعتدت أن المفسر ينظف القمامة خلفك؟ انسَ الأمر. Rust تقول: "أنت سيد ذاكرتك، ولكن لكل خطأ ستدفع ثمنه بعدم الترجمة".
\n\nفي هذه المقالة، سنستعرض 10 أخطاء رئيسية في تعلم Rust يقع فيها المبتدئون. لن نذكرها فقط، بل سنوضح كيفية إصلاحها باستخدام كود حقيقي. إذا كنت قد بدأت للتو رحلتك مع Rust أو واجهت بعض الصعوبات، فهذا المحتوى لك.
\n\nالخطأ رقم 1: تجاهل borrow checker
\n\nالشكوى الأكثر شيوعًا: "لماذا يشتكي المترجم من كل شيء؟!". Borrow checker ليس عدوك، بل أفضل صديق لك. يمنعك من إطلاق النار على قدمك. المشكلة أن المبتدئين يحاولون تجاوزه بدلاً من فهم منطقه.
\n\nكيف يبدو الخطأ النموذجي
\n\nfn main() {\n let mut s = String::from("hello");\n let r1 = &s;\n let r2 = &mut s; // خطأ!\n println!("{}, {}", r1, r2);\n}\n\nسيصدر المترجم: cannot borrow `s` as mutable because it is also borrowed as immutable. المبتدئ في حالة ذعر يحذف mut أو يبدأ في استخدام clone(). الحل الصحيح هو تضييق نطاق الاقتراضات.
الإصلاح
\n\nfn main() {\n let mut s = String::from("hello");\n let r1 = &s;\n println!("{}", r1); // الاقتراض غير القابل للتغيير ينتهي هنا\n let r2 = &mut s;\n println!("{}", r2);\n}\n\nنصيحة: تعامل مع borrow checker كشريك غيور، يسمح باقتراض واحد قابل للتغيير أو أي عدد من الاقتراضات غير القابلة للتغيير، ولكن ليس في نفس الوقت.
\n\nالخطأ رقم 2: الخوف من lifetimes (أوقات الحياة)
\n\nترميز lifetimes يخيف المبتدئين أكثر من أي شيء آخر. بناء الجملة 'a يبدو كالسحر، لكنه في الواقع مجرد تعليقات توضيحية لـ borrow checker تقول: "هذا المرجع يعيش بنفس مدة ذاك".
المشكلة: إرجاع مرجع من دالة
\n\nfn longest(x: &str, y: &str) -> &str { // خطأ: missing lifetime specifier\n if x.len() > y.len() { x } else { y }\n}\n\nالمترجم لا يعرف أي من المرجعين سيتم إرجاعه. الحل هو تحديد أن كلا المرجعين يعيشان بنفس المدة:
\n\nfn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n if x.len() > y.len() { x } else { y }\n}\n\nاختراق: في 90% من الحالات، يمكنك حذف lifetimes، فالمترجم يستنتجها بنفسه (elision). إذا طلبها، فقط أضف 'a ولا داعي للذعر.
الخطأ رقم 3: الإفراط في استخدام clone()
\n\nعندما لا يسمح borrow checker، يلجأ المبتدئون إلى .clone(). هذا يعمل، لكنه يقتل الميزة الرئيسية لـ Rust وهي التجريدات بدون تكلفة. يبدأ الكود في التباطؤ واستهلاك الذاكرة.
مثال سيء
\n\nlet s1 = String::from("hello");\nlet s2 = s1.clone(); // لماذا؟!\nprintln!("{}", s1); // يعمل فقط بسبب clone\n\n\nالأفضل استخدام الاقتراض أو النقل:
\n\nlet s1 = String::from("hello");\nlet s2 = &s1; // اقتراض\nprintln!("{}", s1); // كل شيء بخير\n\n\nالقاعدة الذهبية: استخدم clone() فقط مع هياكل البيانات المعقدة حيث يكون الاقتراض مستحيلًا (مثل عند الإرسال إلى مؤشر ترابط آخر).
\n\nالخطأ رقم 4: عدم فهم الملكية (ownership)
\n\nRust هي اللغة الوحيدة حيث الملكية ليست فلسفة، بل قاعدة ترجمة. كل قيمة لها مالك واحد فقط. عندما ي