खोज…


परिचय

लक्षण एक 'अनुबंध' का वर्णन करने का एक तरीका है जो एक struct को लागू करना चाहिए। लक्षण आमतौर पर विधि हस्ताक्षरों को परिभाषित करते हैं, लेकिन विशेषता के अन्य तरीकों के आधार पर कार्यान्वयन भी प्रदान कर सकते हैं, इसके लिए विशेषता सीमा प्रदान करते हैं।

ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग से परिचित लोगों के लिए, लक्षणों को कुछ सूक्ष्म अंतरों के साथ इंटरफेस के रूप में सोचा जा सकता है।

वाक्य - विन्यास

  • विशेषता विशेषता {fn विधि (...) -> रिटर्न टाइप; ...}
  • विशेषता विशेषता: बाध्य {fn विधि (...) -> रिटर्न टाइप; ...}
  • आघात के लिए टाइप {fn विधि (...) -> रिटर्न टाइप {...} ...}
  • प्रत्यारोपण <टी> टी के लिए विशेषता जहां टी: सीमा {fn विधि (...) -> रिटर्न टाइप {...}} ...}

टिप्पणियों

  • लक्षण आमतौर पर इंटरफेस की तुलना में हैं, लेकिन दोनों के बीच अंतर करना महत्वपूर्ण है। जावा जैसी OO भाषाओं में, इंटरफेस उन कक्षाओं का एक अभिन्न हिस्सा हैं जो उन्हें विस्तारित करते हैं। जंग में, संकलक को किसी संरचना के लक्षणों का कुछ भी पता नहीं होता है जब तक कि उन लक्षणों का उपयोग नहीं किया जाता है।

मूल बातें

एक लक्षण बनाना

trait Speak {
    fn speak(&self) -> String;
}

एक विशेषता को लागू करना

struct Person;
struct Dog;

impl Speak for Person {
    fn speak(&self) -> String {
        String::from("Hello.")
    }
}

impl Speak for Dog {
    fn speak(&self) -> String {
        String::from("Woof.")
    }
}

fn main() {
    let person = Person {};
    let dog = Dog {};
    println!("The person says {}", person.speak());
    println!("The dog says {}", dog.speak());
}

स्टेटिक और डायनेमिक डिस्पैच

एक फ़ंक्शन बनाना संभव है जो उन वस्तुओं को स्वीकार करता है जो एक विशिष्ट विशेषता को लागू करते हैं।

स्टेटिक डिस्पैच

fn generic_speak<T: Speak>(speaker: &T) {
    println!("{0}", speaker.speak());
}

fn main() {
    let person = Person {};
    let dog = Dog {};

    generic_speak(&person);
    generic_speak(&dog);
}

यहां स्टेटिक डिस्पैच का उपयोग किया जाता है, जिसका अर्थ है कि रस्ट कंपाइलर Dog और Person प्रकार दोनों के लिए generic_speak फ़ंक्शन के विशेष संस्करण उत्पन्न करेगा। संकलन के दौरान एक पॉलीमॉर्फ़िक फ़ंक्शन (या किसी भी पॉलीमॉर्फिक इकाई) के विशेष संस्करणों की इस पीढ़ी को मोनोमोर्फाइज़ेशन कहा जाता है।

गतिशील डिस्पैच

fn generic_speak(speaker: &Speak) {
    println!("{0}", speaker.speak());
}

fn main() {
    let person = Person {};
    let dog = Dog {};

    generic_speak(&person as &Speak);
    generic_speak(&dog); // gets automatically coerced to &Speak
}

यहाँ, संकलित बाइनरी में generic_speak का केवल एक ही संस्करण मौजूद है, और रनटाइम पर generic_speak speak() कॉल एक वाइबेट लुकअप का उपयोग करके किया जाता है। इस प्रकार, गतिशील प्रेषण का उपयोग तेजी से संकलन और संकलित बाइनरी के छोटे आकार में होता है, जबकि रनटाइम में थोड़ा धीमा होता है।

प्रकार &Speak या Box<Speak> वस्तुओं को विशेषता वस्तु कहा जाता है

संबद्ध प्रकार

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

सृष्टि

trait GetItems {
    type First;
//  ^~~~ defines an associated type. 
    type Last: ?Sized;
//           ^~~~~~~~ associated types may be constrained by traits as well
    fn first_item(&self) -> &Self::First;
//                           ^~~~~~~~~~~ use `Self::` to refer to the associated type 
    fn last_item(&self) -> &Self::Last;
//                          ^~~~~~~~~~ associated types can be used as function output...
    fn set_first_item(&mut self, item: Self::First);
//                                     ^~~~~~~~~~~  ... input, and anywhere.
}

अंतर्गत प्रयोग

impl<T, U: ?Sized> GetItems for (T, U) {
    type First = T;
    type Last = U;
//              ^~~ assign the associated types
    fn first_item(&self) -> &Self::First { &self.0 }
    fn last_item(&self) -> &Self::Last { &self.1 }
    fn set_first_item(&mut self, item: Self::First) { self.0 = item; }
}

impl<T> GetItems for [T; 3] {
    type First = T;
    type Last = T;
    fn first_item(&self) -> &T { &self[0] }
//                           ^ you could refer to the actual type instead of `Self::First`
    fn last_item(&self) -> &T { &self[2] }
    fn set_first_item(&mut self, item: T) { self[0] = item; }
}

संबंधित प्रकारों का संदर्भ लेना

अगर हमें यकीन है कि GetItems एक प्रकार T लागू हो जाता है, तो हम संबंधित प्रकार को प्राप्त करने के लिए केवल T::First उपयोग कर सकते हैं।

fn get_first_and_last<T: GetItems>(obj: &T) -> (&T::First, &T::Last) {
//                                               ^~~~~~~~ refer to an associated type
    (obj.first_item(), obj.last_item())
}

अन्यथा, आपको संकलक को स्पष्ट रूप से बताने की आवश्यकता है कि कौन सा प्रकार लागू हो रहा है

let array: [u32; 3] = [1, 2, 3];
let first: &<[u32; 3] as GetItems>::First = array.first_item();
//          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [u32; 3] may implement multiple traits which many
//                                        of them provide the `First` associated type.
//                                        thus the explicit "cast" is necessary here.
assert_eq!(*first, 1);

जुड़े प्रकारों के साथ विवश

fn clone_first_and_last<T: GetItems>(obj: &T) -> (T::First, T::Last)
    where T::First: Clone, T::Last: Clone
//  ^~~~~ use the `where` clause to constraint associated types by traits
{
    (obj.first_item().clone(), obj.last_item().clone())
}

fn get_first_u32<T: GetItems<First=u32>>(obj: &T) -> u32 {
//                          ^~~~~~~~~~~ constraint associated types by equality
    *obj.first_item()
}

डिफ़ॉल्ट तरीके

trait Speak {
    fn speak(&self) -> String {
        String::from("Hi.")
    }
}

विधि को डिफ़ॉल्ट रूप से बुलाया जाएगा, सिवाय इसके कि यह impl ब्लॉक में ओवरराइट किया गया है।

struct Human;
struct Cat;

impl Speak for Human {}

impl Speak for Cat {
    fn speak(&self) -> String {
        String::from("Meow.")
    }
}

fn main() {
    let human = Human {};
    let cat = Cat {};
    println!("The human says {}", human.speak());
    println!("The cat says {}", cat.speak());
}

आउटपुट:

मानव कहता है हाय।

बिल्ली मेव कहती है।

एक निशान पर एक बंधन रखकर

नई विशेषता को परिभाषित करते समय यह लागू करना संभव है कि इस विशेषता को लागू करने के इच्छुक लोग कई बाधाओं या सीमाओं को सत्यापित करते हैं।

मानक पुस्तकालय से एक उदाहरण लेते हुए DerefMut विशेषता की आवश्यकता है कि एक प्रकार पहले अपने भाई को लागू Deref विशेषता:

pub trait DerefMut: Deref {
    fn deref_mut(&mut self) -> &mut Self::Target;
}

यह, बदले में, DerefMut को Deref द्वारा परिभाषित संबंधित प्रकार के Target का उपयोग करने में सक्षम बनाता है।


जबकि वाक्यविन्यास विरासत की याद दिला सकता है:

  • यह सभी संबंधित वस्तुओं (स्थिरांक, प्रकार, कार्य, ...) को संबंधित विशेषता में लाता है
  • यह &DerefMut से &DerefMut तक बहुरूपता को सक्षम &Deref

यह प्रकृति में अलग है:

  • एक आजीवन (जैसे 'static ) को एक बाउंड के रूप में उपयोग करना संभव है
  • बाध्य विशेषता आइटम को ओवरराइड करना संभव नहीं है (फ़ंक्शन भी नहीं)

इस प्रकार इसे एक अलग अवधारणा के रूप में सोचना सबसे अच्छा है।

एकाधिक बाध्य वस्तु प्रकार

स्टेटिक डिस्पैच फ़ंक्शन में कई ऑब्जेक्ट प्रकार जोड़ना संभव है।

fn mammal_speak<T: Person + Dog>(mammal: &T) {
    println!("{0}", mammal.speak());
}

fn main() {
    let person = Person {};
    let dog = Dog {};

    mammal_speak(&person);
    mammal_speak(&dog);
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow