Rust: main.rs و lib.rs — كيف لا تتشوش في الوحدات وتسريع الكود

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

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

ابدأ الدورة

ارتباك وحدات Rust: كيف يسبب main.rs و lib.rs الجنون (وكيفية إصلاح ذلك)

\n\n

هل سبق لك أن كتبت كودًا بلغة Rust، وأنشأت مشروعًا جديدًا، وأضفت main.rs و lib.rs — وفجأة بدأ المترجم في إصدار أخطاء تبدو غير منطقية؟ مألوف؟ إذا كنت قد بحثت في Google عن "Rust modules confusion when there is main.rs and lib.rs"، فأنت لست وحدك. هذا السؤال على Stack Overflow حصل على آلاف المشاهدات، وليس من دون سبب. الارتباك مع الوحدات هو واحد من أكثر المشاكل شيوعًا بين المبتدئين (وحتى المطورين ذوي الخبرة الذين ينتقلون من لغات أخرى).

\n\n

في هذه المقالة، لن نقوم فقط بتحليل كيفية عمل نظام الوحدات في Rust. بل سنوضح كيف يؤثر تنظيمها الصحيح بشكل مباشر على تحسين وأداء الكود الخاص بك. ستتعلم لماذا lib.rs ليس مجرد "ملف آخر"، بل أداة قوية لتسريع الترجمة وإنشاء واجهة برمجة تطبيقات (API) نظيفة. هيا بنا!

\n\n

المشكلة: "لماذا لا يرى المترجم الوحدات الخاصة بي؟"

\n\n

تخيل: لقد أنشأت مشروعًا my_project باستخدام cargo new my_project. افتراضيًا، يقوم Cargo بإنشاء src/main.rs. تقوم بإضافة ملف ثانٍ — src/lib.rs — وتكتب فيه دالة. ثم تحاول استدعاءها من main.rs — وتحصل على الخطأ:

\n\n
error[E0432]: unresolved import `my_project::some_function`\n --> src/main.rs:1:5\n  |\n1 | use my_project::some_function;\n  |     ^^^^^^^^^^^^^^^^^^^^^^^^^ no `some_function` in the root
\n\n

ألم مألوف؟ ما المشكلة؟ الأمر بسيط: Rust يعتبر main.rs و lib.rs جذرين مختلفين للـ crate. إذا لم يتم تحديد خلاف ذلك في Cargo.toml، يقوم Cargo تلقائيًا بإنشاء اثنين من الـ crates: crate ثنائي (من main.rs) و crate مكتبة (من lib.rs). لا "يرون" بعضهم البعض بشكل مباشر حتى تقوم بتحديد التبعيات بشكل صريح.

\n\n

هذا هو بالضبط ارتباك وحدات Rust الذي يتحدث عنه الجميع. ولكن بدلاً من الغضب، دعنا نحول هذه "الميزة" إلى ميزة.

\n\n

الحل: كيفية تنظيم الوحدات بشكل صحيح

\n\n

هناك طريقتان، ويعتمد الاختيار على هدفك. لكننا سنقدم لك حرقًا فوريًا: الطريقة الثانية — أفضل للأداء.

\n\n

الخيار 1: كل شيء في crate واحد (بسيط، لكنه غير قابل للتوسع)

\n\n

إذا كان مشروعك صغيرًا، يمكنك تعريف الوحدات داخل main.rs باستخدام mod:

\n\n
// src/main.rs\nmod utils; // يبحث عن src/utils.rs أو src/utils/mod.rs\n\nfn main() {\n    utils::do_something();\n}
\n\n

هذا يعمل، ولكن إذا أضفت lib.rs، سيبدأ الارتباك. سيصبح lib.rs crate منفصلاً، ولن تكون الوحدات من main.rs متاحة فيه. مناسبة للنصوص الصغيرة — لا، للمشاريع الجادة.

\n\n

الخيار 2: مكتبة + ثنائي (الطريق الصحيح للتحسين)

\n\n

الطريقة الأكثر فعالية هي جعل lib.rs المستودع الرئيسي للمنطق، و main.rs غلافًا رفيعًا للتشغيل. بهذه الطريقة تحصل على:

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

كيف تفعل ذلك؟ ببساطة:

\n
// src/lib.rs\npub mod utils;\n\npub fn run() {\n    utils::do_something();\n}\n\n// src/main.rs\nfn main() {\n    my_project::run(); // my_project — اسم الـ crate من Cargo.toml\n}
\n\n

لاحظ: main.rs الآن يستخدم my_project::run(). هذا يعمل لأن Cargo يرى lib.rs كمكتبة باسم my_project. فويلا — اختفى الارتباك!

\n\n

التحسين والأداء: لماذا lib.rs هو صديقك

\n\n

الآن الجزء الأهم

المدونات

توصيات الكتب