2017-02-08 6 views
6

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

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) { 
     use_trait(self); 
    } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 
} 

fn main() { 
    Struct().provided(); 
} 

कौन सा है, तथापि, does not compile की तर्ज पर कोड है, त्रुटि के साथ:

error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied 
--> <anon>:9:19 
    | 
9 |   use_trait(self); 
    |     ^^^^ the trait `std::marker::Sized` is not implemented for `Self` 
    | 
    = help: consider adding a `where Self: std::marker::Sized` bound 
    = note: required for the cast to the object type `Trait` 

मुझे समझ में क्यों यह गारंटी नहीं है कि किसी एक अनवधि प्रकार के लिए विशेषता को लागू नहीं होगा (&T where T: Trait से &Trait में कनवर्ट करने की आवश्यकता T: Sized है, लेकिन घोषणा की आवश्यकता नहीं है)।

हालांकि, सलाह जो मुझे चाहिए वह नहीं करेगी। मैं

fn needed(&self) -> &str where Self: Sized 

जोड़ सकते हैं, लेकिन फिर needed() विधि &Trait (Trait : ?Sized क्योंकि) है, जो बात बेकार renders पर सुलभ हो नहीं होगा, क्योंकि प्रकार (वास्तविक एक है कि कुछ उपयोगी करता है) हमेशा होता हैArc<Trait> के रूप में संभाला गया। और

trait Trait: Sized 

जोड़ने भी बदतर है, (ताकि Trait प्रकार करता है नहीं विशेषता Trait लागू, Trait के रूप में एक प्रकार अनवधि है) है, क्योंकि है कि सभी पर &Trait अनुमति नहीं देता है।

बेशक

मैं बस

fn use_trait<T: Trait>(x: &T) 

कर सकते हैं लेकिन वहाँ वास्तविक कोड में इसके पीछे एक बहुत है, इसलिए मैं monomorphisation वहाँ नहीं करना चाहता, खासकर जब से विशेषता अन्यथा हमेशा विशेषता वस्तु के रूप में नियंत्रित किया जाता है।

क्या जंग को बताने का कोई तरीका है कि impl Trait के सभी प्रकारों का आकार होना चाहिए और यहां एक विधि की परिभाषा है जो उन सभी के लिए काम करनी चाहिए?

+0

यह भी देखें [जंग ट्राइट ऑब्जेक्ट रूपांतरण] (http://stackoverflow.com/q/41604107/155423) – Shepmaster

उत्तर

0
@JoshuaEntrekin's answer की

बढ़ी संस्करण:

सहायक as_trait समारोह एक सहायक विशेषता Trait को लागू करने की कोशिश कर सभी Sized प्रकार के लिए कंबल कार्यान्वयन हो जाता है कि में रखा जा सकता। फिर Trait के कार्यान्वयनकर्ता को कुछ विशेष और रूपांतरण कार्य करने की आवश्यकता नहीं है।

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait : AsTrait { 
    fn needed(&self) -> &str; 

    fn provided(&self) where Self : AsTrait { 
     use_trait(self.as_trait()); 
    } 
} 

trait AsTrait { 
    fn as_trait(&self) -> &Trait; 
} 

impl<T : Trait + Sized> AsTrait for T { 
    fn as_trait(&self) -> &Trait { self } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 
} 

fn main() { 
    Struct().provided(); 
} 

(play पर)।

यह भी बस सहायक विशेषता में provided डाल करने के लिए संभव हो जाएगा, लेकिन तब यह गतिशील Self अनावश्यक रूप से की अन्य पद्धतियों की प्रेषण करने के लिए होगा।


अद्यतन: वास्तव में, मुद्दा यह है कि यह अभी भी provided ओवरराइड करने के लिए संभव हो जाना चाहिए है।

अब उपरोक्त इसे सामान्य बनाकर आगे बढ़ाया जा सकता है। std::makrer::Unsize है, जो इस लेखन के समय अस्थिर है। हम

trait Trait : Unsize<Trait> 

कर सकते हैं नहीं है, क्योंकि जंग CRTP अनुमति नहीं है, लेकिन सौभाग्य से यह पद्धति पर बाधा डाल करने के लिए पर्याप्त है। तो

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) where Self: AsObj<Trait> { 
     use_trait(self.as_obj()); 
    } 
} 

trait AsObj<Tr: ?Sized> { 
    fn as_obj(&self) -> &Trait; 
} 

// For &'a Type for Sized Type 
impl<Type: Trait> AsObj<Trait> for Type { 
    fn as_obj(&self) -> &Trait { self } 
} 

// For trait objects 
impl AsObj<Trait> for Trait { 
    fn as_obj(&self) -> &Trait { self } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 

    fn provided(&self) { 
     println!("Aber dieses Objekt sagt Grüß Gott, Welt!"); // pardon my German, it is rusty. 
    } 
} 

fn main() { 
    let s: &Trait = &Struct(); 
    s.provided(); 
} 

(play पर)

यह अंत में यह अन्य संस्करणों के कार्यान्वयन करने के लिए पारदर्शी बनाता है।

this users thread भी देखें।

2

आप Trait और इसके कार्यान्वयन पर एक अतिरिक्त as_trait समारोह की जरूरत है:

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) { 
     use_trait(self.as_trait()); 
    } 

    fn as_trait(&self) -> &Trait; 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 

    fn as_trait(&self) -> &Trait { 
     self as &Trait 
    } 
} 

आप इसे खेल के मैदान पर कोशिश कर सकते हैं। (trait objects)

+0

"एक अनसुलझा प्रकार" विशेषता वस्तुओं का आकार होता है; दो 'उपयोग'। एक वस्तु के बिना, एक नंगे विशेषता, एक unsized प्रकार है। –

+0

क्या आप समझा सकते हैं कि 'as_trait()' विधि की आवश्यकता क्यों है, और 'use_trait (स्वयं के रूप में और विशेषता)' 'प्रदान किए गए()' में सीधे काम नहीं करता है? –

+0

@ChrisEmerson, मैं स्वयं प्रश्न के स्पष्टीकरण को जोड़ दूंगा। यह बहुत स्पष्ट है कि यह सरल तरीके से क्यों काम नहीं करता है। –

संबंधित मुद्दे