Rust: وظيفي أم كائني التوجه؟ نختار الأسلوب للكود المثالي

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

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

ابدأ الدورة

مقدمة: عالمين في لغة واحدة

\n\n

عندما تبدأ في تعلم Rust، ستلاحظ بسرعة موقعها الفريد. هذه اللغة لا تفرض عليك طريقة واحدة في التفكير. على عكس Java (حيث كل شيء هو كائن) أو Haskell (حيث كل شيء هو دالة)، تقدم لك Rust حرية الاختيار. ولكن مع هذه الحرية تأتي المسؤولية: أي أسلوب تختار - الوظيفي أم الكائني التوجه؟

\n\n

العديد من المطورين القادمين إلى Rust من عالم Python أو C++، ينجذبون بشكل حدسي نحو OOP (البرمجة الكائنية التوجه). إنهم يبحثون عن الفئات، الوراثة والأنماط المألوفة. آخرون، مستلهمين من عالم Haskell أو Scala، يحاولون البرمجة بلغة Rust حصريًا بالأسلوب الوظيفي، باستخدام المونادات، الثبات والتركيب.

\n\n

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

\n\n

أساسيات OOP في Rust: السمات بدلاً من الفئات

\n\n

دعنا نضع النقاط على الحروف فورًا. لا توجد فئات في Rust بالمعنى التقليدي. لكن هذا لا يعني أنه لا يمكنك استخدام OOP. بدلاً من الفئات، تُستخدم هنا السمات (traits) والهياكل (structs). هي التي تسمح بتحقيق التغليف، تعدد الأشكال وحتى بعض الشبه بالوراثة.

\n\n

الهياكل والطرق

\n\n

الهياكل هي "الكائنات" الخاصة بك. تقوم بتعريف البيانات، ثم باستخدام impl تضيف إليها الطرق:

\n\n
struct Player {\n    name: String,\n    health: i32,\n    level: u32,\n}\n\nimpl Player {\n    // طريقة المُنشئ\n    fn new(name: &str) -> Self {\n        Player {\n            name: name.to_string(),\n            health: 100,\n            level: 1,\n        }\n    }\n\n    // طريقة تغير الحالة\n    fn take_damage(&mut self, damage: i32) {\n        self.health = (self.health - damage).max(0);\n    }\n\n    // دالة الوصول (getter)\n    fn is_alive(&self) -> bool {\n        self.health > 0\n    }\n}\n
\n\n

هذا هو أسلوب OOP الخالص: لدينا حالة (حقول الهيكل) وسلوك (طرق). توفر Rust التغليف من خلال التحكم في الرؤية (معدل pub).

\n\n

تعدد الأشكال عبر السمات

\n\n

بدلاً من وراثة الفئات، يُستخدم في Rust تعدد الأشكال عبر السمات. هذا أقوى وأكثر أمانًا من الوراثة التقليدية، حيث لا تواجه "مشكلة الماس" أو وراثة سلوك غير مرغوب فيه عن طريق الصدفة.

\n\n
trait Attackable {\n    fn attack(&self, target: &mut Player);\n}\n\nstruct Swordsman {\n    damage: i32,\n}\n\nimpl Attackable for Swordsman {\n    fn attack(&self, target: &mut Player) {\n        target.take_damage(self.damage);\n        println!("ألحق المبارز {} ضررًا!", self.damage);\n    }\n}\n\nstruct Mage {\n    spell_power: i32,\n    mana_cost: i32,\n}\n\nimpl Attackable for Mage {\n    fn attack(&self, target: &mut Player) {\n        target.take_damage(self.spell_power * 2);\n        println!("أطلق الساحر كرة نارية بقوة {}!", self.spell_power * 2);\n    }\n}\n
\n\n

الآن يمكنك العمل مع أي كائن يطبق السمة Attackable، دون القلق بشأن نوعه المحدد:

\n\n
fn perform_attack(attacker: &impl Attackable, target: &mut Player) {\n    attacker.attack(target);\n}\n
\n\n

يُسمى هذا "الكتابة البطية على المنشطات" أو تعدد الأشكال الثابت. تتحقق Rust من كل شيء في مرحلة الترجمة، لذلك لن تحصل على خطأ في وقت التشغيل.

\n\n

الأسلوب الوظيفي: المكررات والإغلاقات

\n\n

الآن ننتقل

المدونات

توصيات الكتب