ربط السلاسل النصية في Rust: أفضل 5 أخطاء للمبتدئين (وكيفية تجنبها)

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا لا يمكنك ببساطة جمع السلاسل النصية في Rust؟

\n\n

إذا كنت قد انتقلت إلى Rust من Python أو JavaScript، فإن أول ما قد يصدمك على الأرجح هو محاولة كتابة "Hello, " + "world!". يستقبلك المترجم بموجة حمراء ورسالة خطأ غامضة. في عالم Python، كان هذا سيعمل فوراً، لكن Rust هو وحش مختلف. لقد حصد سؤال "How do I concatenate strings?" على Stack Overflow مئات الآلاف من المشاهدات، وهذا ليس من قبيل الصدفة.

\n\n

المشكلة تكمن في أن ربط السلاسل النصية في Rust ليس مجرد سكر نحوي. إنها مسألة إدارة الذاكرة، والملكية (ownership)، وأنواع البيانات. إذا كنت مبتدئاً، يمكنك بسهولة أن تخطو على الأخطاء الكلاسيكية: فقدان ملكية سلسلة نصية، أو نسخ غيغابايتات من البيانات عن طريق الخطأ، أو ببساطة الخلط بين String و &str.

\n\n

في هذه المقالة، سنستعرض أكثر 5 أخطاء شيوعاً التي يرتكبها المبتدئون عند ربط السلاسل النصية في Rust، ونوضح كيفية تجنبها. ستتعرف على متى تستخدم +، ومتى تستخدم format!، ومتى تستخدم push_str. هيا بنا!

\n\n

الخطأ رقم 1: نسيان أخذ الملكية (ownership)

\n\n

كيف يبدو هذا

\n\n

تخيل أنك تكتب الكود التالي:

\n\n
let s1 = String::from("مرحباً");\nlet s2 = String::from("، أيها العالم!");\nlet s3 = s1 + &s2; // خطأ؟ أم لا؟\nprintln!("{}", s1); // خطأ في الترجمة!
\n\n

تتوقع أن يظل s1 متاحاً، لكن المترجم يقول: "لا، لقد تم نقل (moved) s1".

\n\n

جوهر الخطأ

\n\n

في Rust، يستخدم عامل التشغيل + للسلاسل النصية التوقيع fn add(self, s: &str) -> String. لاحظ self — هذا يعني أن السلسلة الأولى تُستهلك (consumes) ولم يعد بإمكانك استخدامها. أنت حرفياً "تتنازل" عن s1 للدالة add، وتصبح غير متاحة.

\n\n

كيفية الإصلاح

\n\n

هناك طريقتان:

\n\n
    \n
  • استنساخ السلسلة النصية (إذا كنت بحاجة إلى السلسلة الأصلية): let s3 = s1.clone() + &s2;
  • \n
  • تغيير الترتيب أو استخدام format!:
  • \n
\n\n
let s1 = String::from("مرحباً");\nlet s2 = String::from("، أيها العالم!");\nlet s3 = format!("{}{}", s1, s2); // s1 و s2 يظلان متاحين\nprintln!("{}", s1); // يعمل!
\n\n

نصيحة: إذا كنت لا تخطط لاستخدام s1 بعد الربط، فاستخدم + بثقة. هذا أسرع من format!، لأنه لا ينشئ مخزناً مؤقتاً جديداً من الصفر.

\n\n

الخطأ رقم 2: الخلط بين String و &str

\n\n

كيف يبدو هذا

\n\n

تحاول جمع String مع نص حرفي (literal):

\n\n
let s = String::from("Hello");\nlet result = s + " world"; // يعمل!
\n\n

لكن إذا حاولت العكس:

\n\n
let s = "Hello";\nlet result = s + String::from(" world"); // خطأ!
\n\n

جوهر الخطأ

\n\n

عامل التشغيل + يعمل فقط عندما يكون الجزء الأيسر هو String، والجزء الأيمن هو &str. النص الحرفي " world" هو تلقائياً من نوع &str، لذلك يعمل المثال الأول. في المثال الثاني، s هو من نوع &str، وليس لديه طريقة add.

\n\n

كيفية الإصلاح

\n\n

قم بتحويل &str إلى String أو استخدم format!:

\n\n
let s = "Hello";\nlet result = format!("{} {}", s, "world"); // طريقة شاملة\n// أو\nlet result = s.to_string() + " world"; // to_string() تنشئ String
\n\n

القاعدة الذهبية: String هو نوع مالك (owned)، &str هو استعارة (borrow). الربط يتطلب دائماً ملكية على الجانب الأيسر.

\n\n

الخطأ رقم 3

المدونات

توصيات الكتب