एक संबंधित प्रकार बनाम एक सामान्य प्रकार का उपयोग करना कब उचित है?


108

में इस सवाल का , एक मुद्दा पैदा हुई है कि एक संबद्ध प्रकार में एक सामान्य प्रकार पैरामीटर का उपयोग करने का प्रयास बदलकर हल किया जा सकता। इससे यह सवाल उठता है कि "एक संबद्ध प्रकार यहां अधिक उपयुक्त क्यों है?", जिसने मुझे और जानना चाहा।

संबंधित प्रकारों को प्रस्तुत करने वाला RFC कहता है:

यह RFC द्वारा स्पष्ट विशेषता मिलान को स्पष्ट करता है:

  • इनपुट प्रकार के रूप में सभी लक्षण प्रकार के मापदंडों का इलाज करना , और
  • संबंधित प्रकार प्रदान करना, जो आउटपुट प्रकार हैं

RFC एक प्रेरक उदाहरण के रूप में एक ग्राफ संरचना का उपयोग करता है, और यह प्रलेखन में भी उपयोग किया जाता है , लेकिन मैं प्रकार-पैरामीटर संस्करण पर संबंधित प्रकार के संस्करण के लाभों की पूरी तरह से सराहना नहीं करना चाहता हूं। प्राथमिक बात यह है कि इस distanceपद्धति के Edgeप्रकार की देखभाल करने की आवश्यकता नहीं है । यह अच्छा है, लेकिन सभी प्रकार से जुड़े होने का एक कारण उथला लगता है।

मैंने अभ्यास में उपयोग करने के लिए संबद्ध प्रकार को बहुत सहज होना पाया है, लेकिन मैं खुद को संघर्ष करते हुए पाता हूं कि मुझे अपने एपीआई में कहां और कब उपयोग करना चाहिए।

कोड लिखते समय, मुझे सामान्य प्रकार के पैरामीटर पर संबंधित प्रकार का चयन कब करना चाहिए, और मुझे इसके विपरीत कब करना चाहिए?

जवाबों:


75

अब इसे द रस्ट प्रोग्रामिंग लैंग्वेज के दूसरे संस्करण में छुआ गया है । हालांकि, इसके अलावा थोड़ा सा गोता लगाते हैं।

आइए हम एक सरल उदाहरण से शुरू करते हैं।

किसी विशेषता विधि का उपयोग करना कब उचित है?

देर से बाध्यकारी प्रदान करने के कई तरीके हैं :

trait MyTrait {
    fn hello_word(&self) -> String;
}

या:

struct MyTrait<T> {
    t: T,
    hello_world: fn(&T) -> String,
}

impl<T> MyTrait<T> {
    fn new(t: T, hello_world: fn(&T) -> String) -> MyTrait<T>;

    fn hello_world(&self) -> String {
        (self.hello_world)(self.t)
    }
}

किसी भी कार्यान्वयन / प्रदर्शन की रणनीति की उपेक्षा करते हुए, ऊपर दिए गए दोनों अंश उपयोगकर्ता को एक गतिशील तरीके से निर्दिष्ट करने की अनुमति देते हैं कि कैसे hello_worldव्यवहार करना चाहिए।

एक अंतर (शब्दार्थ) यह है कि traitकार्यान्वयन इस बात की गारंटी देता है कि किसी दिए गए प्रकार को Tलागू करने के लिए trait, hello_worldहमेशा एक ही व्यवहार होगा जबकि structकार्यान्वयन प्रति उदाहरण के आधार पर एक अलग व्यवहार रखने की अनुमति देता है।

किसी विधि का उपयोग करना उचित है या नहीं यह usecase पर निर्भर करता है!

संबद्ध प्रकार का उपयोग करना कब उचित है?

इसी तरह करने के लिए traitउपरोक्त विधियों, एक संबद्ध प्रकार देर बंधन का एक रूप है (हालांकि यह संकलन पर होता है), के उपयोगकर्ता की अनुमति के traitकिसी दिए गए उदाहरण है, जिसमें प्रकार स्थानापन्न करने के लिए निर्दिष्ट करने के लिए। यह एकमात्र तरीका नहीं है (इस प्रकार प्रश्न):

trait MyTrait {
    type Return;
    fn hello_world(&self) -> Self::Return;
}

या:

trait MyTrait<Return> {
    fn hello_world(&Self) -> Return;
}

उपरोक्त विधियों के देर से बंधन के बराबर हैं:

  • पहले एक को लागू करता है कि किसी दिए गए के लिए Selfनहीं है एक भी Returnजुड़े
  • इसके बजाय दूसरा, कई MyTraitके Selfलिए लागू करने की अनुमति देता हैReturn

कौन सा रूप अधिक उपयुक्त है यह इस बात पर निर्भर करता है कि यह एकता को लागू करने के लिए समझ में आता है या नहीं। उदाहरण के लिए:

  • Deref एक संबद्ध प्रकार का उपयोग करता है क्योंकि एकता के बिना कंपाइलर अनुमान के दौरान पागल हो जाएगा
  • Add एक संबद्ध प्रकार का उपयोग करता है क्योंकि इसके लेखक ने सोचा था कि दोनों तर्क दिए जाने पर तार्किक रिटर्न प्रकार होगा

जैसा कि आप देख सकते हैं, जबकि Derefएक स्पष्ट usecase (तकनीकी बाधा) है, का मामला Addकम स्पष्ट है: शायद यह या i32 + i32तो उपज के लिए या संदर्भ के आधार पर समझ में आता है? बहरहाल, लेखक ने अपने फैसले का प्रयोग किया और निर्णय लिया कि अतिरिक्त प्रकार के अतिरिक्त रिटर्न को लोड करना अनावश्यक था।i32Complex<i32>

मेरा निजी रुख है कि कोई सही जवाब नहीं है। फिर भी, एकता तर्क से परे, मैं उल्लेख करता हूं कि संबद्ध प्रकार विशेषता का उपयोग करना आसान बनाते हैं क्योंकि वे निर्दिष्ट किए जाने वाले मापदंडों की संख्या को कम करते हैं, इसलिए यदि नियमित रूप से विशेषता पैरामीटर का उपयोग करने के लचीलेपन के लाभ स्पष्ट नहीं हैं, तो मैं संबद्ध प्रकार से शुरू करने का सुझाव दें।


4
मुझे थोड़ा सरल बनाने की कोशिश करें: trait/struct MyTrait/MyStructबिल्कुल एक impl MyTrait forया अनुमति देता है impl MyStructtrait MyTrait<Return>कई implएस की अनुमति देता है क्योंकि यह सामान्य है। Returnकिसी भी प्रकार का हो सकता है जेनेरिक संरचनाएं समान हैं।
पॉल-सेबेस्टियन मैनोल

2
मुझे "द रस्ट प्रोग्रामिंग लैंग्वेज" की तुलना में आपके उत्तर को समझने में बहुत आसान लगता है
ड्रॉजफ

"पहला व्यक्ति यह बताता है कि किसी दिए गए स्व के लिए एक एकल रिटर्न जुड़ा हुआ है"। यह तात्कालिक अर्थों में सही है, लेकिन एक निश्चित रूप से एक सामान्य लक्षण के साथ उपवर्ग द्वारा इस प्रतिबंध पर काम किया जा सकता है। शायद एकता केवल एक सुझाव हो सकती है, और लागू नहीं
joel

36

एसोसिएटेड प्रकार एक कर रहे हैं तंत्र समूहीकरण , तो वे इस्तेमाल किया जाना चाहिए, जब यह एक साथ समूह प्रकार के लिए समझ में आता है।

Graphविशेषता दस्तावेज में पेश किया इस का एक उदाहरण है। तुम एक चाहते हैं Graphसामान्य हो, लेकिन एक बार आप एक विशेष प्रकार की है Graph, तो आप नहीं करना चाहते हैं Nodeया Edgeप्रकार अब अलग-अलग हो सकते हैं। एक विशेष रूप Graphसे एक ही कार्यान्वयन के भीतर उन प्रकारों को अलग नहीं करना चाहते हैं, और वास्तव में, वे हमेशा एक ही होना चाहते हैं। वे एक साथ समूहीकृत हैं, या कोई भी संबद्ध कह सकता है ।


4
मुझे समझने में थोड़ा समय लगा। मेरे लिए यह एक ही बार में कई प्रकारों को परिभाषित करने जैसा लगता है: एज और नोड का ग्राफ से कोई मतलब नहीं है।
तफिया
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.