परिचय: एक भाषा में दो दुनियाएँ
\n\nजब आप Rust सीखना शुरू करते हैं, तो आप जल्दी ही इसकी अनोखी स्थिति देखते हैं। यह भाषा आपको सोचने का एक ही तरीका नहीं थोपती। Java (जहाँ सब कुछ ऑब्जेक्ट है) या Haskell (जहाँ सब कुछ फंक्शन है) के विपरीत, Rust आपको चुनने की आज़ादी देता है। लेकिन इस आज़ादी के साथ ज़िम्मेदारी भी आती है: कौन सा दृष्टिकोण चुनें — फंक्शनल या ऑब्जेक्ट-ओरिएंटेड?
\n\nPython या C++ की दुनिया से Rust में आने वाले कई डेवलपर्स सहज रूप से OOP (ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग) की ओर आकर्षित होते हैं। वे क्लासेस, इनहेरिटेंस और परिचित पैटर्न खोजते हैं। वहीं, Haskell या Scala की दुनिया से प्रेरित अन्य लोग, मोनाड, इम्यूटेबिलिटी और कम्पोज़ीशन का उपयोग करके केवल फंक्शनल स्टाइल में Rust लिखने की कोशिश करते हैं।
\n\nसच्चाई, हमेशा की तरह, बीच में है। Rust एक मल्टी-पैराडाइम भाषा है जो आपको दोनों दुनियाओं का सर्वश्रेष्ठ लेने की अनुमति देती है। इस लेख में, हम जानेंगे कि Rust में फंक्शनल दृष्टिकोण का प्रभावी ढंग से उपयोग कैसे करें और कब ऑब्जेक्ट-ओरिएंटेड पैटर्न लागू करें। आप सीखेंगे कि ऐसा कोड कैसे लिखें जो न केवल काम करे बल्कि अपनी सुंदरता से मन मोह ले।
\n\nRust में OOP की बुनियाद: क्लासेस के बजाय ट्रेट्स
\n\nचलिए सीधे बात करते हैं। Rust में क्लासिकल अर्थों में क्लासेस नहीं हैं। लेकिन इसका मतलब यह नहीं है कि आप OOP का उपयोग नहीं कर सकते। क्लासेस के बजाय यहाँ ट्रेट्स (traits) और स्ट्रक्चर्स (structs) का उपयोग किया जाता है। ये ही आपको एनकैप्सुलेशन, पॉलीमॉर्फिज्म और यहाँ तक कि इनहेरिटेंस जैसी सुविधाएँ प्रदान करते हैं।
\n\nस्ट्रक्चर्स और मेथड्स
\n\nस्ट्रक्चर्स आपके 'ऑब्जेक्ट' हैं। आप डेटा को परिभाषित करते हैं, और फिर impl की मदद से उनमें मेथड्स जोड़ते हैं:
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 // गेटर (एक्सेस मेथड)\n fn is_alive(&self) -> bool {\n self.health > 0\n }\n}\n\n\nयह शुद्ध OOP-शैली है: हमारे पास स्थिति (स्ट्रक्चर के फील्ड) और व्यवहार (मेथड्स) है। Rust विजिबिलिटी कंट्रोल (pub मॉडिफायर) के माध्यम से एनकैप्सुलेशन सुनिश्चित करता है।
ट्रेट्स के माध्यम से पॉलीमॉर्फिज्म
\n\nक्लास इनहेरिटेंस के बजाय, Rust ट्रेट्स के माध्यम से पॉलीमॉर्फिज्म का उपयोग करता है। यह क्लासिकल इनहेरिटेंस से अधिक शक्तिशाली और सुरक्षित है, क्योंकि आपको 'डायमंड प्रॉब्लम' या अनावश्यक व्यवहार विरासत में लेने जैसी समस्याओं का सामना नहीं करना पड़ता।
\n\ntrait 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 ट्रेट को लागू करता है, बिना उसके विशिष्ट प्रकार की चिंता किए:
fn perform_attack(attacker: &impl Attackable, target: &mut Player) {\n attacker.attack(target);\n}\n\n\nइसे 'स्टेरॉयड पर डक टाइपिंग' या स्टैटिक पॉलीमॉर्फिज्म कहा जाता है। Rust सब कुछ कंपाइल टाइम पर जाँचता है, इसलिए आपको रनटाइम में कोई त्रुटि नहीं मिलेगी।
\n\nफंक्शनल दृष्टिकोण: इटरेटर और क्लोजर
\n\nअब स्विच करते हैं