البرمجة الوصفية في Rust: الماكروسات وقوة الكود على مستوى جديد

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

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

ابدأ الدورة

مقدمة: لماذا يستطيع Rust السحر بالكود؟

\n\n

هل سبق لك أن كتبت كودًا بلغة Rust وشعرت أنك تكرر نفس الإنشاءات لعشرات الهياكل؟ أو هل أردت توليد تنفيذ trait تلقائيًا دون نسخ الكود يدويًا؟ مرحبًا بك في عالم البرمجة الوصفية في Rust — التقنيات التي تسمح لك بكتابة كود يكتب كودًا.

\n\n

لا تمتلك Rust انعكاسًا كاملاً أثناء التنفيذ (مثل Java أو Python)، لكنها تقدم شيئًا أكثر قوة وأمانًا — الماكروسات. تعمل هذه في مرحلة التجميع، حيث تحلل وتحول شجرة التركيب المجردة (AST). وهذا يعطي إمكانيات لا تصدق للتحسين وتقليل الكود المتكرر دون فقدان الأداء.

\n\n

في هذه المقالة، سنشرح التقنيات المتقدمة للبرمجة الوصفية: من macro_rules! الكلاسيكية إلى الماكروسات الإجرائية الكاملة. ستتعلم كيفية إنشاء سمات الاشتقاق الخاصة بك وكتابة ماكروسات سمة تغير دلالات الكود. هيا بنا!

\n\n

الماكروسات التصريحية: macro_rules! ليست مجرد "استبدال نص"

\n\n

يعتقد الكثيرون أن macro_rules! هي معالج نص بدائي. في الواقع، إنها نظام مطابقة أنماط قوي يعمل على مستوى الرموز. تسمح بإنشاء لغات خاصة بالمجال (DSL) مباشرة داخل Rust.

\n\n

مثال متقدم: إنشاء باني باستخدام ماكرو

\n\n

تخيل أنك بحاجة إلى إنشاء "باني" (builder) لهيكل. بدلاً من كتابة عشرات الدوال، يمكنك كتابة ماكرو واحد:

\n\n
macro_rules! builder {\n    ($struct_name:ident, { $($field:ident: $field_type:ty),* $(,)? }) => {\n        struct $struct_name {\n            $($field: Option<$field_type>),*\n        }\n\n        impl $struct_name {\n            $(\n                pub fn $field(mut self, value: $field_type) -> Self {\n                    self.$field = Some(value);\n                    self\n                }\n            )*\n\n            pub fn build(self) -> Result<Self, String> {\n                $(\n                    if self.$field.is_none() {\n                        return Err(format!("الحقل {} مطلوب", stringify!($field)));\n                    }\n                )*\n                Ok(self)\n            }\n        }\n    };\n}\n\nbuilder!(Config, {\n    host: String,\n    port: u16,\n    timeout: u64,\n});\n\nfn main() {\n    let config = Config {\n        host: None,\n        port: None,\n        timeout: None,\n    }\n    .host("localhost".to_string())\n    .port(8080)\n    .build()\n    .unwrap();\n    println!("التكوين جاهز: {}:{}", config.host.unwrap(), config.port.unwrap());\n}\n
\n\n

هذا الماكرو لا يولد الحقول فقط، بل يضيف أيضًا التحقق من الحقول الإجبارية. لاحظ stringify!($field) — فهو يحول المعرف إلى سلسلة نصية في مرحلة التجميع. هذه تقنية نموذجية من البرمجة الوصفية المتقدمة في Rust.

\n\n

التكرارات: $(...)* في العمل

\n\n

صيغة التكرار تسمح بمعالجة قوائم الوسائط بأي طول. من خلال دمج ident و ty و expr و "أجزاء" أخرى، يمكنك إنشاء أنماط معقدة. على سبيل المثال، ماكرو لإنشاء enum مع تنفيذ تلقائي لـ Display:

\n\n
macro_rules! display_enum {\n    ($enum_name:ident, { $($variant:ident => $desc:expr),* $(,)? }) => {\n        enum $enum_name {\n            $($variant),*\n        }\n\n        impl std::fmt::Display for $enum_name {\n            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n                match self {\n                    $(Self::$variant => write!(f, "{}", $desc)),*\n                }\n            }\n        }\n    };\n}\n\ndisplay_enum!(Status, {\n    Active => "status_active",\n    Inactive => "status_inactive",\n    Pending => "s                

المدونات

توصيات الكتب