शब्द "फैट पॉइंटर" का उपयोग संदर्भ और कच्चे पॉइंटर्स को गतिशील रूप से आकार (डीएसटी) - स्लाइस या विशेषता वस्तुओं को संदर्भित करने के लिए किया जाता है । एक फैट पॉइंटर में पॉइंटर प्लस कुछ जानकारी होती है जो DST को "पूर्ण" (जैसे लंबाई) बनाती है।
रस्ट में आमतौर पर उपयोग किए जाने वाले अधिकांश प्रकार डीएसटी नहीं हैं , लेकिन एक निश्चित आकार का संकलन समय पर जाना जाता है। ये प्रकार लक्षण को लागू करते हैंSized
। यहां तक कि प्रकार जो डायनेमिक आकार के ढेर बफर (जैसे Vec<T>
) का प्रबंधन करते हैं, Sized
जैसे कि कंपाइलर जानता है कि बाइट्स की सटीक संख्या एक Vec<T>
उदाहरण ढेर पर लग जाएगी। वर्तमान में Rust में चार अलग-अलग प्रकार के DST हैं।
स्लाइस ( [T]
और str
)
प्रकार [T]
(किसी के लिए T
) गतिशील रूप से आकार है (इसलिए विशेष "स्ट्रिंग टुकड़ा" प्रकार है str
)। इसलिए आप आमतौर पर इसे केवल एक संदर्भ के रूप में &[T]
या &mut [T]
अर्थात के रूप में देखते हैं । यह संदर्भ एक तथाकथित "वसा सूचक" है। चलो देखते है:
dbg!(size_of::<&u32>());
dbg!(size_of::<&[u32; 2]>());
dbg!(size_of::<&[u32]>());
यह प्रिंट (कुछ सफाई के साथ):
size_of::<&u32>() = 8
size_of::<&[u32; 2]>() = 8
size_of::<&[u32]>() = 16
तो हम देखते हैं कि सामान्य प्रकार u32
का एक संदर्भ 8 बाइट्स जैसा है, जैसा कि एक सरणी के संदर्भ में है [u32; 2]
। वे दो प्रकार डीएसटी नहीं हैं। लेकिन जैसा [u32]
कि एक डीएसटी है, इसका संदर्भ दोगुना बड़ा है। स्लाइस के मामले में, DST को "पूरा" करने वाला अतिरिक्त डेटा केवल लंबाई है। तो कोई कह सकता है कि प्रतिनिधित्व &[u32]
कुछ इस तरह है:
struct SliceRef {
ptr: *const u32,
len: usize,
}
विशेषता वस्तुओं ( dyn Trait
)
ट्रिट ऑब्जेक्ट्स के रूप में ट्रिट का उपयोग करते समय (जैसे कि मिटाया गया, गतिशील रूप से भेजा गया), ये ट्रांजिट ऑब्जेक्ट डीएसटी हैं। उदाहरण:
trait Animal {
fn speak(&self);
}
struct Cat;
impl Animal for Cat {
fn speak(&self) {
println!("meow");
}
}
dbg!(size_of::<&Cat>());
dbg!(size_of::<&dyn Animal>());
यह प्रिंट (कुछ सफाई के साथ):
size_of::<&Cat>() = 8
size_of::<&dyn Animal>() = 16
फिर से, &Cat
केवल 8 बाइट्स बड़े हैं क्योंकि Cat
एक सामान्य प्रकार है। लेकिन dyn Animal
एक विशेषता है और इसलिए गतिशील रूप से आकार। जैसे, &dyn Animal
16 बाइट्स बड़ी है।
विशेषता वस्तुओं के मामले में, DST को पूरा करने वाला अतिरिक्त डेटा vtable (vptr) के लिए एक संकेतक है। मैं पूरी तरह से यहाँ vtables और vptrs की अवधारणा की व्याख्या नहीं कर सकता, लेकिन वे इस आभासी प्रेषण संदर्भ में सही विधि कार्यान्वयन को कॉल करने के लिए उपयोग किए जाते हैं। वीआईबीटी डेटा का एक स्थिर टुकड़ा है जिसमें मूल रूप से प्रत्येक विधि के लिए केवल फ़ंक्शन पॉइंटर होता है। इसके साथ, मूल रूप से एक विशेषता वस्तु के संदर्भ को निम्न रूप में दर्शाया गया है:
struct TraitObjectRef {
data_ptr: *const (),
vptr: *const (),
}
(यह C ++ से अलग है, जहां अमूर्त वर्गों के लिए vptr को ऑब्जेक्ट के भीतर संग्रहीत किया जाता है। दोनों दृष्टिकोणों के फायदे और नुकसान हैं।)
कस्टम डीएसटी
वास्तव में यह संभव है कि एक ऐसा ढांचा तैयार किया जाए जिसमें एक आखिरी क्षेत्र एक डीएसटी हो। हालांकि यह दुर्लभ है, हालांकि। एक प्रमुख उदाहरण है std::path::Path
।
कस्टम DST का एक संदर्भ या सूचक भी एक वसा सूचक है। अतिरिक्त डेटा संरचना के अंदर डीएसटी के प्रकार पर निर्भर करता है।
अपवाद: बाहरी प्रकार
में आरएफसी 1861 , extern type
सुविधा शुरू की गई थी। बाहरी प्रकार भी डीएसटी हैं, लेकिन उनके लिए संकेत वसा बिंदु नहीं हैं । या अधिक बिल्कुल, जैसा कि RFC डालता है:
जंग में, डीएसटी को इंगित किए गए ऑब्जेक्ट के बारे में डीएसटी के लिए संकेत मेटाडेटा ले जाते हैं। स्ट्रिंग्स और स्लाइस के लिए यह बफर की लंबाई है, विशेषता वस्तुओं के लिए यह ऑब्जेक्ट की वाइबेट है। बाहरी प्रकारों के लिए मेटाडेटा बस है ()
। इसका मतलब यह है कि बाहरी प्रकार के लिए एक सूचक का आकार एक ही है usize
(यानी यह "वसा सूचक" नहीं है)।
लेकिन अगर आप सी इंटरफेस के साथ बातचीत नहीं कर रहे हैं, तो आप शायद कभी भी इन बाहरी प्रकारों से नहीं निपटेंगे।
ऊपर, हमने अपरिवर्तनीय संदर्भों के लिए आकार देखे हैं। फैट पॉइंटर्स परस्पर संदर्भों, अपरिवर्तनीय रॉ पॉइंटर्स और म्यूटेबल रॉ पॉइंटर्स के लिए समान कार्य करते हैं:
size_of::<&[u32]>() = 16
size_of::<&mut [u32]>() = 16
size_of::<*const [u32]>() = 16
size_of::<*mut [u32]>() = 16