2017-07-13 18 views
6

मैं अक्सर नए प्रकार के पैटर्न का उपयोग करता हूं, लेकिन मैं my_type.0.call_to_whatever(...) लिखने से थक गया हूं। मैं Deref विशेषता को कार्यान्वित करने के लिए प्रेरित हूं क्योंकि यह सरल कोड लिखने की अनुमति देता है क्योंकि मैं अपने नए प्रकार का उपयोग कर सकता हूं जैसे कि यह कुछ स्थितियों में अंतर्निहित प्रकार था, उदा।:क्या इसे नए प्रकार के लिए डेफ को लागू करने के लिए एक बुरा अभ्यास माना जाता है?

use std::ops::Deref; 

type Underlying = [i32; 256]; 
struct MyArray(Underlying); 

impl Deref for MyArray { 
    type Target = Underlying; 

    fn deref(&self) -> &Self::Target { 
     &self.0 
    } 
} 

fn main() { 
    let my_array = MyArray([0; 256]); 

    println!("{}", my_array[0]); // I can use my_array just like a regular array 
} 

क्या यह एक अच्छा या बुरा अभ्यास है? क्यूं कर? डाउनसाइड्स क्या हो सकता है?

उत्तर

7

मुझे लगता है कि यह खराब अभ्यास है।

के बाद से मैं अपने newtype उपयोग कर सकते हैं जैसे कि यह कुछ स्थितियों

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

आपके पास कोई नियंत्रण नहीं है कि क्या है और अंतर्निहित प्रकार से क्या उपलब्ध नहीं है; सब कुछ है। आपके उदाहरण में, क्या आप लोगों को as_ptr पर कॉल करने की अनुमति देना चाहते हैं? sort के बारे में क्या? मुझे यकीन है कि आप उम्मीद करते हैं, क्योंकि वे कर सकते हैं!

सब आप कर सकते हैं के बारे में तरीकों अधिलेखित करने के लिए प्रयास है, लेकिन वे अभी भी मौजूद है:

impl MyArray { 
    fn as_ptr(&self) -> *const i32 { 
     panic!("No, you don't!") 
    } 
} 

फिर भी, वे अभी भी स्पष्ट रूप से कहा जा सकता है (<[i32]>::as_ptr(&*my_array);)।

मैं इसे उसी कारण से खराब अभ्यास मानता हूं, मुझे विश्वास है कि कोड पुन: उपयोग के लिए विरासत का उपयोग करना बुरा अभ्यास है। आपके उदाहरण में, आप अनिवार्य रूप से एक सरणी से विरासत में हैं। मैं निम्नलिखित रूबी की तरह कुछ कभी नहीं लिखना चाहते हैं:

class MyArray < Array 
    # ... 
end 

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

लेकिन मैं अन्य भाषाओं में लिखने my_type.0.call_to_whatever(...)

तरह के थक गया हूँ, मेरा मानना ​​है कि सही समाधान विरासत से अधिक रचना है। आप एक कॉल अग्रेषित करने के लिए की जरूरत है, newtype पर एक विधि बनाने के लिए:

impl MyArray { 
    fn call_to_whatever(&self) { self.0.call_to_whatever() } 
} 

मुख्य बात यह है कि जंग में इस दर्दनाक बनाता प्रतिनिधिमंडल की कमी है।एक काल्पनिक प्रतिनिधिमंडल वाक्य रचना

impl MyArray { 
    delegate call_to_whatever -> self.0; 
} 

की तरह कुछ हो सकता है तो जब आप Deref/DerefMut इस्तेमाल करना चाहिए? मैं वकालत करता हूं कि केवल एक बार यह समझ में आता है कि जब आप स्मार्ट पॉइंटर लागू कर रहे हैं।


व्यावहारिक रूप से बोलते हुए, मैं newtypes कि कर रहे हैं नहीं परियोजनाओं जहाँ मैं एकमात्र या बहुमत योगदान कर रहा हूँ पर सार्वजनिक रूप से उजागर के लिए उपयोग Deref/DerefMut कर । ऐसा इसलिए है क्योंकि मैं खुद पर भरोसा करता हूं और मेरा क्या मतलब है इसका अच्छा ज्ञान है। अगर प्रतिनिधिमंडल सिंटैक्स मौजूद था, तो मैं नहीं करूँगा।

+1

मुझे कम से कम 'डेफ' के संबंध में असहमत होना है - मेरी अधिकांश नई विशेषताएं पूरी तरह से फैंसी कन्स्ट्रक्टर के रूप में मौजूद हैं, ताकि मैं एक स्थिर गारंटी के साथ डेटा पास कर सकूं कि यह कुछ आविष्कारों को पूरा करता है। यानी, ऑब्जेक्ट का निर्माण हो जाने के बाद, अब मैं वास्तव में नए प्रकार के बारे में परवाह नहीं करता हूं, अंतर्निहित डेटा _only_; पैटर्न मिलान/'.0' हर जगह सिर्फ शोर है, और हर विधि का प्रतिनिधि जो मुझे परवाह है, वह भी होगा। मुझे लगता है कि एक प्रकार का 'डेफ' लागू करना और 'डेफ्रम' नहीं होना आश्चर्यजनक हो सकता है, लेकिन वे सभी कारणों से अलग-अलग लक्षण हैं ... – ildjarn

+1

@ildjarn * एक स्थिर गारंटी के साथ कि यह कुछ आविष्कारों को संतुष्ट करता है * - अगर आप 'DerefMut' को लागू करते हैं, आप अब उन आविष्कारों की स्थिर रूप से गारंटी नहीं दे सकते क्योंकि कोई भी नए प्रकार के क्षेत्रों की दृश्यता के बावजूद उन्हें छोटा रूप से बदल सकता है। यदि आप केवल 'डेफ' को लागू करते हैं, तो भी आप लोगों को अपने डेटा पर पोक करने की अनुमति देते हैं। इससे किसी भी भौतिक हानि का कारण नहीं बनना चाहिए, लेकिन अक्सर आपको एक विस्तृत एपीआई प्रस्तुत करना चाहिए जो आपको बेनकाब करने की आवश्यकता है। – Shepmaster

+0

"* इससे किसी भी भौतिक हानि का कारण नहीं बनना चाहिए, लेकिन अक्सर आपको विस्तृत एपीआई प्रस्तुत करने की आवश्यकता होती है। *" Std :: str' IMO से अधिक नहीं; प्रोटोकॉल काम में, उदाहरण के लिए, आप प्रायः आदिम प्रकारों के अनुक्रमों से निपट रहे हैं, जहां यह अस्पष्ट (/ दूर करने की कोशिश करें) के बजाय व्यर्थ है, _but_ बनाए रखने के लिए सख्त आविष्कार हैं (सीएफ यूटीएफ -8)। मैं इसके बारे में दृढ़ता से महसूस नहीं करता; मुझे लगता है कि "बुरी प्रैक्टिस" इसे मजबूती से रख रही है। : -] (संपादित करें: अगर कोई 'deref_mut' असुरक्षित बना सकता है तो शायद मैं दृढ़ता से महसूस करूंगा क्योंकि' डेफ्रम 'डिफ्रम' कन्फ्रम 'नहीं होगा। – ildjarn

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

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