Rust में Dependency Injection: शुरुआती गाइड और उदाहरण

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: Rust में Dependency Injection क्यों ज़रूरी है?

\n\n

Rust में प्रोग्राम लिखते समय, आपको अक्सर ऐसी स्थिति का सामना करना पड़ेगा जहां एक मॉड्यूल (जैसे, सर्विस या कंट्रोलर) को दूसरे मॉड्यूल (डेटाबेस, API, लॉगर) की क्षमताओं का उपयोग करना होता है। सबसे आसान तरीका है कि ज़रूरत के समय ऑब्जेक्ट को सीधे कोड के अंदर बना लें:

\n\n
struct UserService;\n\nimpl UserService {\n    fn get_user(&self, id: u32) -> String {\n        let db = Database::new(); // ❌ टाइट कपलिंग (tight coupling)\n        db.query_user(id)\n    }\n}\n
\n\n

यह तरीका टाइट कपलिंग (tight coupling) पैदा करता है। कोड को टेस्ट करना, दोबारा इस्तेमाल करना और बदलना मुश्किल हो जाता है। Dependency Injection (DI) एक डिज़ाइन पैटर्न है जिसमें डिपेंडेंसी (निर्भरता) को ऑब्जेक्ट के अंदर बनाने के बजाय बाहर से दी जाती है। Rust, अपनी ओनरशिप सिस्टम और ट्रेट्स के साथ, बिना किसी फ्रेमवर्क के DI को लागू करने के शानदार तरीके प्रदान करता है।

\n\n

इस लेख में, हम व्यावहारिक उदाहरणों के साथ Rust में डिपेंडेंसी इंजेक्ट करना सीखेंगे: स्ट्रक्चर को पास करने से लेकर ट्रेट्स और स्मार्ट पॉइंटर्स के उपयोग तक।

\n\n

1. बेसिक तरीका: कंस्ट्रक्टर के ज़रिए डिपेंडेंसी पास करना

\n\n

Rust में डिपेंडेंसी इंजेक्ट करने का सबसे सरल तरीका है कि इसे कंस्ट्रक्टर या फंक्शन के आर्गुमेंट के रूप में पास करें। आइए एक लॉगर के उदाहरण से समझते हैं।

\n\n

खराब उदाहरण (DI के बिना)

\n\n
struct ConsoleLogger;\n\nimpl ConsoleLogger {\n    fn log(&self, msg: &str) {\n        println!("[LOG]: {}", msg);\n    }\n}\n\nstruct OrderService {\n    logger: ConsoleLogger, // ❌ एक खास टाइप से बंधा हुआ\n}\n\nimpl OrderService {\n    fn new() -> Self {\n        Self {\n            logger: ConsoleLogger, // अंदर ही बना रहे हैं\n        }\n    }\n\n    fn place_order(&self, item: &str) {\n        self.logger.log(&format!("ऑर्डर: {}", item));\n    }\n}\n
\n\n

अच्छा उदाहरण (DI के साथ)

\n\n
struct ConsoleLogger;\n\nimpl ConsoleLogger {\n    fn log(&self, msg: &str) {\n        println!("[LOG]: {}", msg);\n    }\n}\n\nstruct OrderService {\n    logger: ConsoleLogger, // डिपेंडेंसी बाहर से आ रही है\n}\n\nimpl OrderService {\n    // कंस्ट्रक्टर डिपेंडेंसी को स्वीकार करता है\n    fn new(logger: ConsoleLogger) -> Self {\n        Self { logger }\n    }\n\n    fn place_order(&self, item: &str) {\n        self.logger.log(&format!("ऑर्डर: {}", item));\n    }\n}\n\nfn main() {\n    let logger = ConsoleLogger;\n    let service = OrderService::new(logger);\n    service.place_order("Rust की किताब");\n}\n
\n\n

क्या बदला? अब OrderService खुद लॉगर नहीं बनाता। उसे तैयार लॉगर मिलता है। यह DI है, लेकिन एक समस्या है: हम अब भी ConsoleLogger टाइप से बंधे हैं। कोड को लचीला बनाने के लिए, हमें ट्रेट्स का उपयोग करना होगा।

\n\n

2. डिपेंडेंसी को एब्सट्रैक्ट करने के लिए ट्रेट्स का उपयोग

\n\n

Rust में ट्रेट्स (traits) दूसरी भाषाओं के इंटरफेस की तरह हैं। ये एक कॉन्ट्रैक्ट (अनुबंध) को परिभाषित करते हैं जिसका पालन डिपेंडेंसी को करना होता है।

\n\n

Logger ट्रेट को परिभाषित करना

\n\n
trait Logger {\n    fn log(&self, msg: &str);\n}\n\nstruct ConsoleLogger;\nimpl Logger for ConsoleLogger {\n    fn log(&self, msg: &str) {\n        println!("[कंसोल]: {}", msg);\n    }\n}\n\nstruct FileLogger {\n    filename: String,\n}\nimpl Logger for FileLogger {\n    fn log(&self, msg: &str) {\n        // फ़ाइल में लिखने का अनुकरण\n        println!("[फ़ाइल {}]: {}", self.filename, msg);\n    }\n}\n
\n\n

जेनेरिक्स (generics) के ज़रिए ट्रेट को इंजेक्ट करना

\n\n
struct OrderService<L: Logger> {\n    logger: L, // जेनेरिक टाइप जो Logger ट्रेट को लागू करता है\n}\n\nimpl<L: Logger> OrderService<L> {\n    fn new(logger: L) -> Self {\n        Self { logger }\n    }\n\n    fn place_order(&self, item: &str) {\n        self.logger.log(&format!("ऑर्डर: {}", item));\n    }\n}\n\nfn main() {\n    let console_logge                

ब्लॉग

पुस्तक अनुशंसाएँ