أعلام الميزات في Rust: ضبط مرن دون إعادة ترجمة

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

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

ابدأ الدورة

أعلام الميزات في Rust: السلاح السري للتطوير المرن

\n\n

تخيل أنك تكتب مكتبة للعمل مع الصور. بعض المستخدمين يريدون فقط تغيير الحجم الأساسي، وآخرون يريدون تصحيح الألوان المتقدم، وآخرون يريدون التكامل مع الشبكات العصبية. كيف تجعل الجميع سعداء دون تضخيم الكود أو إنشاء عشرات الإصدارات؟ الإجابة بسيطة — أعلام الميزات (أو مفاتيح الميزات).

\n\n

في عالم Rust، تتحول هذه التقنية إلى فن حقيقي. بفضل نظام الماكرو القوي والتجميع الشرطي، يمكنك إنشاء تطبيقات معيارية قابلة للتكوين تتكيف مع أي سيناريو. ونعم، لن تضطر إلى إعادة ترجمة المشروع بأكمله من أجل ميزة صغيرة واحدة.

\n\n

في هذه المقالة، سنشرح كيفية عمل أعلام الميزات في Rust، ونعرض مزاياها بأمثلة حقيقية ونقدم نصائح عملية. هيا بنا!

\n\n

ما هي أعلام الميزات ولماذا نحتاجها؟

\n\n

أعلام الميزات (أو التجميع الشرطي) هي آلية تسمح بتشغيل أو إيقاف تشغيل أجزاء معينة من الكود في مرحلة البناء. في Rust، يتم تنفيذ ذلك من خلال نظام features في Cargo.toml والتوجيهات #[cfg(feature = "...")].

\n\n

لماذا نحتاج هذا؟ إليك ثلاثة سيناريوهات رئيسية:

\n\n
    \n
  • معيارية المكتبات — يقرر المستخدم بنفسه الوظائف التي يحتاجها.
  • \n
  • الميزات التجريبية — يمكن اختبار وظائف جديدة دون مخاطرة على بيئة الإنتاج.
  • \n
  • الاعتماد على المنصة — كود مختلف لنظام Windows وLinux وmacOS.
  • \n
\n\n

على عكس أعلام وقت التشغيل (التي يتم فحصها أثناء التنفيذ)، تعمل ميزات Cargo في مرحلة التجميع. وهذا يعني أن الكود غير المستخدم لا يدخل حتى في الملف الثنائي — تحصل على أقصى أداء وأقل حجم.

\n\n

كيف تعمل أعلام الميزات في Rust: البنية الأساسية

\n\n

دعنا ننتقل مباشرة إلى الكود. لنفترض أننا نكتب مكتبة image_tools مع دعم اختياري لـ WebP.

\n\n

أولاً، نحدد الميزة في Cargo.toml:

\n\n
[package]\nname = "image_tools"\nversion = "0.1.0"\n\n[features]\ndefault = ["png"]\npng = []\nwebp = []\n
\n\n

الآن في الكود نستخدم السمة #[cfg]:

\n\n
// src/lib.rs\n\n#[cfg(feature = "png")]\npub mod png_processor;\n\n#[cfg(feature = "webp")]\npub mod webp_processor;\n\npub mod common;\n\n// داخل الوحدة:\n#[cfg(feature = "webp")]\npub fn encode_webp(data: &[u8]) -> Vec<u8> {\n    // تنفيذ WebP\n    println!("Encoding WebP...");\n    data.to_vec()\n}\n\n#[cfg(not(feature = "webp"))]\npub fn encode_webp(data: &[u8]) -> Vec<u8> {\n    panic!("WebP support not enabled. Enable 'webp' feature.");\n}\n
\n\n

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

\n\n

تقنيات متقدمة: التركيبات والتبعيات

\n\n

تسمح أعلام الميزات في Rust بإنشاء تسلسلات هرمية معقدة. على سبيل المثال، يمكنك إنشاء ميزة "full" التي تشغل عدة ميزات في وقت واحد:

\n\n
[features]\ndefault = ["basic"]\nbasic = ["resize", "crop"]\nadvanced = ["color_correction", "filters"]\nfull = ["basic", "advanced", "webp"]\n
\n\n

كما يمكنك تحديد تبعيات من صناديق خارجية:

\n\n
[features]\nwebp = ["dep:libwebp-sys"]  # يشمل تبعية النظام\n\n[dependencies]\nlibwebp-sys = { version = "0.1", optional = true }\n
\n\n

هنا optional = true يخبر Cargo أن الصندوق يتم تضمينه فقط عند تفعيل الميزة المقابلة. هذا يوفر وقت البناء ومساحة القرص.

\n\n

أعلام الميزات في مشروع حقيقي: مثال خادم HTTP

\n\n

دعنا نتخيل أننا نكتب إطار عمل مصغر لـ

المدونات

توصيات الكتب