Rust में फैट पॉइंटर्स: फैट पॉइंटर को समझना

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

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

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

"फैट" पॉइंटर के पीछे क्या छिपा है? Rust में फैट पॉइंटर का विश्लेषण

\n\n

कल्पना करें कि आप एक पुस्तकालय में गए और एक किताब मांगी। लाइब्रेरियन आपको एक छोटा सा कागज़ का टुकड़ा देता है जिस पर शेल्फ और रैक का नंबर होता है - यह एक सामान्य पॉइंटर है। लेकिन क्या होगा अगर आपको नहीं पता कि किताब कितनी बड़ी है? या फिर यह तीन खंडों वाली किताब है? आपको दूसरे कागज़ की ज़रूरत होगी: "3 में से खंड 1" या "लंबाई: 450 पृष्ठ"।

\n\n

Rust में, ऐसे "डबल" पॉइंटर को fat pointer (फैट पॉइंटर) कहा जाता है। यह कोई जादू नहीं है, बल्कि संख्याओं की एक जोड़ी है: डेटा का पता और उसकी मेटा-जानकारी (अक्सर लंबाई या विधियों की वर्चुअल टेबल का पॉइंटर)। आइए वास्तविक कोड उदाहरणों के साथ समझें कि इसकी आवश्यकता क्यों है और यह कैसे काम करता है।

\n\n

सामान्य पॉइंटर्स: पतले और तेज़

\n\n

आधार से शुरू करते हैं। Rust में सरल पॉइंटर्स होते हैं - &T (रेफरेंस) या *const T (रॉ पॉइंटर)। वे ठीक 8 बाइट (64-बिट सिस्टम पर) लेते हैं और केवल मेमोरी में पता संग्रहीत करते हैं।

\n\n
fn main() {\n    let x: i32 = 42;\n    let ptr: &i32 = &x; // पतला पॉइंटर — 8 बाइट\n    println!("रेफरेंस का आकार: {} बाइट", std::mem::size_of_val(&ptr));\n}\n
\n\n

आउटपुट: रेफरेंस का आकार: 8 बाइट। सब कुछ अनुमानित है: कंपाइलर जानता है कि i32 4 बाइट है, इसलिए अतिरिक्त जानकारी की आवश्यकता नहीं है। लेकिन क्या होगा अगर डेटा का आकार पहले से ज्ञात नहीं है?

\n\n

पहला फैट पॉइंटर: स्लाइस (&[T])

\n\n

स्लाइस एक ऐरे या वेक्टर में एक "खिड़की" है। लेकिन इसका उपयोग करने के लिए, न केवल शुरुआत बल्कि तत्वों की संख्या भी जानना आवश्यक है। Rust इसे एक जोड़ी (ptr, len) के रूप में संग्रहीत करता है - यही fat pointer है।

\n\n
fn main() {\n    let arr = [1, 2, 3, 4, 5];\n    let slice: &[i32] = &arr[1..4]; // 3 तत्वों का स्लाइस\n\n    println!("स्लाइस का आकार: {} बाइट", std::mem::size_of_val(&slice));\n    println!("तत्व: {:?}", slice);\n}\n
\n\n

आउटपुट: स्लाइस का आकार: 16 बाइट (8 बाइट पॉइंटर + 8 बाइट लंबाई)। यदि हम केवल पता पास करते, तो हमें नहीं पता होता कि कहाँ रुकना है। यही कारण है कि स्लाइस फैट पॉइंटर का एक उत्कृष्ट उदाहरण है।

\n\n

वैसे, स्ट्रिंग &str बिल्कुल उसी तरह काम करती है: यह एक फैट पॉइंटर (*const u8, usize) है। यही कारण है कि &str 16 बाइट लेता है, जबकि &String केवल 8 बाइट लेता है (क्योंकि String स्वयं लंबाई को अंदर संग्रहीत करता है)।

\n\n

दूसरा फैट पॉइंटर: ट्रेट-ऑब्जेक्ट्स (&dyn Trait)

\n\n

Rust में ट्रेट-ऑब्जेक्ट्स के माध्यम से डायनामिक डिस्पैच होता है। जब आप &dyn MyTrait लिखते हैं, तो कंपाइलर नहीं जानता कि कौन सा विशिष्ट प्रकार पास किया जाएगा। सही फ़ंक्शन को कॉल करने के लिए उसे एक वर्चुअल मेथड टेबल (vtable) की आवश्यकता होती है।

\n\n
trait Animal {\n    fn speak(&self);\n}\n\nstruct Dog;\nstruct Cat;\n\nimpl Animal for Dog {\n    fn speak(&self) { println!("भौं!"); }\n}\n\nimpl Animal for Cat {\n    fn speak(&self) { println!("म्याऊं!"); }\n}\n\nfn main() {\n    let dog = Dog;\n    let cat = Cat;\n\n    let animals: [&dyn Animal; 2] = [&dog, &cat];\n\n    println!("&dyn Animal का आकार: {} बाइट", std::mem::size_of::<&dyn Animal>());\n\n    for animal in &animals {\n        animal.speak();\n    }\n}\n
\n\n

आउटपुट: &dyn Animal का आकार: 16 बाइट। ये 16 बाइट फिर से फैट पॉइंटर हैं: पहले 8 बाइट डेटा का पता (Dog या Cat), दूसरे 8 बाइट vtable (विधियों की तालिका) का पता।

\n\n

फैट पॉइंटर प्रदर्शन को कैसे प्रभावित करता है?

\n\n

फैट पॉइंटर्स एक समझौता हैं। एक ओर, वे अधिक जानकारी रखते हैं, जो डायनामिक प्रकारों के साथ काम करने की अनुमति देता है। दूसरी ओर:

\n\n
    \n
  • मेमोरी: फैट पॉइंटर 8 बाइट के बजाय 16 बाइट लेता है। यह गंभीर नहीं है, लेकिन बड़े कलेक्शन में प्रभाव डाल सकता है।
  • \n
  • गति: vtable के माध्यम से एक्सेस (ट्रेट-ऑब्जेक्ट्स के लिए) सीधे मेथड कॉल (मोनोमोर्फिज़ेशन) की तुलना में थोड़ी धीमी है। अंतर

ब्लॉग

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