أعلام الميزات في Rust: السلاح السري للتطوير المرن
\n\nتخيل أنك تكتب مكتبة للعمل مع الصور. بعض المستخدمين يريدون فقط تغيير الحجم الأساسي، وآخرون يريدون تصحيح الألوان المتقدم، وآخرون يريدون التكامل مع الشبكات العصبية. كيف تجعل الجميع سعداء دون تضخيم الكود أو إنشاء عشرات الإصدارات؟ الإجابة بسيطة — أعلام الميزات (أو مفاتيح الميزات).
\n\nفي عالم Rust، تتحول هذه التقنية إلى فن حقيقي. بفضل نظام الماكرو القوي والتجميع الشرطي، يمكنك إنشاء تطبيقات معيارية قابلة للتكوين تتكيف مع أي سيناريو. ونعم، لن تضطر إلى إعادة ترجمة المشروع بأكمله من أجل ميزة صغيرة واحدة.
\n\nفي هذه المقالة، سنشرح كيفية عمل أعلام الميزات في Rust، ونعرض مزاياها بأمثلة حقيقية ونقدم نصائح عملية. هيا بنا!
\n\nما هي أعلام الميزات ولماذا نحتاجها؟
\n\nأعلام الميزات (أو التجميع الشرطي) هي آلية تسمح بتشغيل أو إيقاف تشغيل أجزاء معينة من الكود في مرحلة البناء. في Rust، يتم تنفيذ ذلك من خلال نظام features في Cargo.toml والتوجيهات #[cfg(feature = "...")].
لماذا نحتاج هذا؟ إليك ثلاثة سيناريوهات رئيسية:
\n\n- \n
- معيارية المكتبات — يقرر المستخدم بنفسه الوظائف التي يحتاجها. \n
- الميزات التجريبية — يمكن اختبار وظائف جديدة دون مخاطرة على بيئة الإنتاج. \n
- الاعتماد على المنصة — كود مختلف لنظام Windows وLinux وmacOS. \n
على عكس أعلام وقت التشغيل (التي يتم فحصها أثناء التنفيذ)، تعمل ميزات Cargo في مرحلة التجميع. وهذا يعني أن الكود غير المستخدم لا يدخل حتى في الملف الثنائي — تحصل على أقصى أداء وأقل حجم.
\n\nكيف تعمل أعلام الميزات في Rust: البنية الأساسية
\n\nدعنا ننتقل مباشرة إلى الكود. لنفترض أننا نكتب مكتبة image_tools مع دعم اختياري لـ WebP.
أولاً، نحدد الميزة في Cargo.toml:
[package]\nname = "image_tools"\nversion = "0.1.0"\n\n[features]\ndefault = ["png"]\npng = []\nwebp = []\n\n\nالآن في الكود نستخدم السمة #[cfg]:
// 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" التي تشغل عدة ميزات في وقت واحد:
[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 أن الصندوق يتم تضمينه فقط عند تفعيل الميزة المقابلة. هذا يوفر وقت البناء ومساحة القرص.
أعلام الميزات في مشروع حقيقي: مثال خادم HTTP
\n\nدعنا نتخيل أننا نكتب إطار عمل مصغر لـ