مقدمة: لماذا لا يمكنك ببساطة جمع السلاسل النصية في Rust؟
\n\nإذا كنت قد انتقلت إلى Rust من Python أو JavaScript، فإن أول ما قد يصدمك على الأرجح هو محاولة كتابة "Hello, " + "world!". يستقبلك المترجم بموجة حمراء ورسالة خطأ غامضة. في عالم Python، كان هذا سيعمل فوراً، لكن Rust هو وحش مختلف. لقد حصد سؤال "How do I concatenate strings?" على Stack Overflow مئات الآلاف من المشاهدات، وهذا ليس من قبيل الصدفة.
المشكلة تكمن في أن ربط السلاسل النصية في Rust ليس مجرد سكر نحوي. إنها مسألة إدارة الذاكرة، والملكية (ownership)، وأنواع البيانات. إذا كنت مبتدئاً، يمكنك بسهولة أن تخطو على الأخطاء الكلاسيكية: فقدان ملكية سلسلة نصية، أو نسخ غيغابايتات من البيانات عن طريق الخطأ، أو ببساطة الخلط بين String و &str.
في هذه المقالة، سنستعرض أكثر 5 أخطاء شيوعاً التي يرتكبها المبتدئون عند ربط السلاسل النصية في Rust، ونوضح كيفية تجنبها. ستتعرف على متى تستخدم +، ومتى تستخدم format!، ومتى تستخدم push_str. هيا بنا!
الخطأ رقم 1: نسيان أخذ الملكية (ownership)
\n\nكيف يبدو هذا
\n\nتخيل أنك تكتب الكود التالي:
\n\nlet s1 = String::from("مرحباً");\nlet s2 = String::from("، أيها العالم!");\nlet s3 = s1 + &s2; // خطأ؟ أم لا؟\nprintln!("{}", s1); // خطأ في الترجمة!\n\nتتوقع أن يظل s1 متاحاً، لكن المترجم يقول: "لا، لقد تم نقل (moved) s1".
جوهر الخطأ
\n\nفي Rust، يستخدم عامل التشغيل + للسلاسل النصية التوقيع fn add(self, s: &str) -> String. لاحظ self — هذا يعني أن السلسلة الأولى تُستهلك (consumes) ولم يعد بإمكانك استخدامها. أنت حرفياً "تتنازل" عن s1 للدالة add، وتصبح غير متاحة.
كيفية الإصلاح
\n\nهناك طريقتان:
\n\n- \n
- استنساخ السلسلة النصية (إذا كنت بحاجة إلى السلسلة الأصلية):
let s3 = s1.clone() + &s2;\n - تغيير الترتيب أو استخدام
format!: \n
let s1 = String::from("مرحباً");\nlet s2 = String::from("، أيها العالم!");\nlet s3 = format!("{}{}", s1, s2); // s1 و s2 يظلان متاحين\nprintln!("{}", s1); // يعمل!\n\nنصيحة: إذا كنت لا تخطط لاستخدام s1 بعد الربط، فاستخدم + بثقة. هذا أسرع من format!، لأنه لا ينشئ مخزناً مؤقتاً جديداً من الصفر.
الخطأ رقم 2: الخلط بين String و &str
\n\nكيف يبدو هذا
\n\nتحاول جمع String مع نص حرفي (literal):
let s = String::from("Hello");\nlet result = s + " world"; // يعمل!\n\nلكن إذا حاولت العكس:
\n\nlet s = "Hello";\nlet result = s + String::from(" world"); // خطأ!\n\nجوهر الخطأ
\n\nعامل التشغيل + يعمل فقط عندما يكون الجزء الأيسر هو String، والجزء الأيمن هو &str. النص الحرفي " world" هو تلقائياً من نوع &str، لذلك يعمل المثال الأول. في المثال الثاني، s هو من نوع &str، وليس لديه طريقة add.
كيفية الإصلاح
\n\nقم بتحويل &str إلى String أو استخدم format!:
let s = "Hello";\nlet result = format!("{} {}", s, "world"); // طريقة شاملة\n// أو\nlet result = s.to_string() + " world"; // to_string() تنشئ String\n\nالقاعدة الذهبية: String هو نوع مالك (owned)، &str هو استعارة (borrow). الربط يتطلب دائماً ملكية على الجانب الأيسر.