मेरे पास एक बंद है, जिसका मैं निर्माण करता हूं:

let r = receiver.clone();
let is_channel_empty = move || -> bool { r.is_empty() };

और फिर के माध्यम से इंजेक्ट करें:

Adapter::new(is_channel_empty)

एडेप्टर इस तरह दिखता है:

type ChannelEmptyFn = dyn Fn() -> bool + Send + Sync;
// for Box: type ChannelEmptyFn = Box<dyn Fn() -> bool + Send + Sync + 'static>;
pub struct Adapter {
    is_channel_empty: ChannelEmptyFn,
}
impl Adapter {
    pub fn new(is_channel_empty: ChannelEmptyFn) -> Self
    {
        Self { is_channel_empty }
    }
}

मुझे रनटाइम त्रुटि पर स्पष्ट, आकार ज्ञात नहीं हो रहा है। अगर मैं एक संदर्भ पास करता हूं, तो उसे जीवन भर की आवश्यकता होती है और 'स्थैतिक काम नहीं करेगा। अगर मैं एक बॉक्स पास करता हूं, तो यह आवंटित ढेर हो जाता है, और जब मुझे ढेर आवंटन पसंद नहीं है, तो यह एक आसान समाधान है। क्या कोई दूसरा विकल्प है? मैं एक fn (फ़ंक्शन पॉइंटर) पास नहीं कर सकता क्योंकि क्लोजर में एक कैप्चर किया गया वातावरण है। क्या फ़ील्ड प्रकार को बंद करने के रूप में निर्दिष्ट करने का कोई तरीका है? Fn, FnMut, या FnOnce के अलावा? मैं बस सोच रहा हूं कि क्या मुझे जंग के अपने सीमित ज्ञान में कुछ याद आ रहा है।

एक आखिरी बात, एडेप्टर अंततः एक आर्क में लिपटा हुआ है, फिर यहाँ कुछ विडंबना है, जो कि दूसरा कारण है कि मैं इसे एक ही ब्लॉक में आवंटित करना चाहता हूं।

1
Bruce 26 नवम्बर 2020, 03:26

1 उत्तर

सबसे बढ़िया उत्तर

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

जेनरिक संकलन-समय हैं, जबकि विशेषता वस्तुएं गतिशील (रन-टाइम) हैं, जो एक आवश्यक रन-टाइम लागत लेती है, जिसे रस्ट द्वारा स्पष्ट किया गया है।

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

यदि आप एक एडेप्टर को दूसरे के लिए एक्सचेंज नहीं करना चाहते हैं, तो जेनरिक आपके लिए एकदम सही है।

pub struct Adapter<F: Fn() -> bool + Send + Sync> {
    is_channel_empty: F,
}
impl<F: Fn() -> bool + Send + Sync> Adapter<F> {
    pub fn new(is_channel_empty: F) -> Self
    {
        Self { is_channel_empty }
    }
}

यदि आप रन-टाइम पर क्लोजर या एडॉप्टर को किसी अन्य के लिए एक्सचेंज करने में सक्षम होना चाहते हैं, तो आपको गतिशील होने की आवश्यकता है, जैसे आपके पास अभी है।

आपको बंद को अप्रत्यक्ष की एक परत के पीछे रखना होगा, ताकि इसके आकार को सुरक्षित रूप से चारों ओर से बदला जा सके। आप संदर्भ मार्ग पर जा सकते हैं, लेकिन जैसा कि आपने कहा, आपको जीवन भर की आवश्यकता है, और यह आर्क के साथ काम नहीं करेगा, क्योंकि आर्क को अपनी सामग्री (स्थिर जीवनकाल) की आवश्यकता है। अज्ञात आकार की किसी चीज़ के मालिक होने का एकमात्र तरीका एक बॉक्स है, क्योंकि ढेर गतिशील है। यदि आप गतिशील होते हैं, तो आपको अक्सर सभी तरह से प्रतिबद्ध होना चाहिए। यदि आवश्यक हो तो ढेर आवंटन के आसपास कोई रास्ता नहीं है। ढेर आवंटन बुरा नहीं है, यह आपके टूलबॉक्स में एक और उपकरण है, जिसमें अधिकांश क्लोजर मामलों में अधिक लागत नहीं लगती है क्योंकि इसे केवल गतिशील प्रेषण तालिका और कैप्चर किए गए चर, यदि कोई हो, के लिए आवंटित करने की आवश्यकता होती है।

आर्क पर रस्ट डॉक्यूमेंटेशन से:

आर्क प्रकार T के मान का साझा स्वामित्व प्रदान करता है, जिसे ढेर में आवंटित किया जाता है।

2
RedBorg 26 नवम्बर 2020, 18:15