इसकी प्रतिलिपि बनाना अक्सर आवश्यक होता है रूबी में मूल्य. हालांकि यह सरल लग सकता है, और यह साधारण वस्तुओं के लिए है, जैसे ही आपको डेटा की एक प्रति बनानी होगी एक ही वस्तु पर कई सरणी या हैश के साथ संरचना, आप जल्दी से पाएंगे कि कई हैं नुकसान।
ऑब्जेक्ट और संदर्भ
यह समझने के लिए कि क्या चल रहा है, आइए कुछ सरल कोड देखें। सबसे पहले, POD (Plain Old Data) प्रकार का उपयोग कर असाइनमेंट ऑपरेटर माणिक.
a = १
बी = ए
ए + = 1
डालता है
यहां, असाइनमेंट ऑपरेटर के मान की एक प्रति बना रहा है ए और इसे असाइन करना ख असाइनमेंट ऑपरेटर का उपयोग करना। को कोई भी परिवर्तन ए इसमें परिलक्षित नहीं होगा ख. लेकिन कुछ और जटिल के बारे में क्या? इस पर विचार करो।
a = [1,2]
बी = ए
एक << 3
b.inspect डालता है
उपरोक्त कार्यक्रम चलाने से पहले, यह अनुमान लगाने की कोशिश करें कि आउटपुट क्या होगा और क्यों होगा। यह पिछले उदाहरण के समान नहीं है, इसमें किए गए परिवर्तन ए में परिलक्षित होते हैं ख, लेकिन क्यों? इसकी वजह है सरणी ऑब्जेक्ट POD प्रकार नहीं है। असाइनमेंट ऑपरेटर मूल्य की एक प्रति नहीं बनाता है, यह बस कॉपी करता है संदर्भ एरे ऑब्जेक्ट के लिए।
ए तथा ख अब चर रहे हैं संदर्भ समान ऐरे ऑब्जेक्ट, दोनों में से किसी भी परिवर्तनशील परिवर्तन को दूसरे में देखा जाएगा।और अब आप देख सकते हैं कि अन्य वस्तुओं के संदर्भों के साथ गैर-तुच्छ वस्तुओं की नकल करना मुश्किल क्यों हो सकता है। यदि आप बस वस्तु की एक प्रति बनाते हैं, तो आप केवल गहरी वस्तुओं के संदर्भ की नकल कर रहे हैं, इसलिए आपकी प्रतिलिपि को "उथली प्रति" कहा जाता है।
रूबी क्या प्रदान करता है: डुबकी और क्लोन
रूबी वस्तुओं की प्रतियां बनाने के लिए दो तरीके प्रदान करता है, जिनमें से एक गहरी प्रतियां करने के लिए बनाया जा सकता है। वस्तु # dup विधि किसी वस्तु की उथली प्रतिलिपि बनाएगी। इसे प्राप्त करने के लिए, dup विधि कॉल करेगा initialize_copy उस वर्ग की विधि। यह वास्तव में वर्ग पर निर्भर करता है। कुछ वर्गों में, जैसे कि एरे, यह मूल सरणी के समान सदस्यों के साथ एक नई सरणी को आरंभीकृत करेगा। यह, हालांकि, एक गहरी प्रतिलिपि नहीं है। निम्नलिखित को धयान मे रखते हुए।
a = [1,2]
b = a.dup
एक << 3
b.inspect डालता है
a = [[१,२]]
b = a.dup
एक [0] << 3
b.inspect डालता है
यहाँ क्या हुआ है? सरणी # initialize_copy विधि वास्तव में एक ऐरे की एक प्रति बनाएगी, लेकिन वह प्रति स्वयं एक उथली प्रति है। यदि आपके पास उपयोग करते हुए आपके सरणी में कोई अन्य गैर-POD प्रकार हैं dup केवल आंशिक रूप से गहरी प्रतिलिपि होगी। यह केवल पहली सरणी जितनी गहरी होगी, जितनी गहरी होगी सरणियों, हैश या अन्य वस्तुओं को केवल उथले कॉपी किया जाएगा।
उल्लेख के लायक एक और तरीका है, क्लोन. क्लोन विधि वैसा ही काम करती है dup एक महत्वपूर्ण अंतर के साथ: यह उम्मीद की जाती है कि ऑब्जेक्ट इस पद्धति को एक के साथ ओवरराइड करेंगे जो गहरी प्रतियां कर सकते हैं।
तो व्यवहार में इसका क्या अर्थ है? इसका मतलब है कि आपकी प्रत्येक कक्षा एक क्लोन पद्धति को परिभाषित कर सकती है जो उस वस्तु की गहरी प्रतिलिपि बनाएगी। इसका मतलब यह भी है कि आपको अपने द्वारा बनाए गए प्रत्येक वर्ग के लिए एक क्लोन विधि लिखना होगा।
एक ट्रिक: मार्शल
किसी वस्तु को "अनुक्रमित" करने का एक अन्य तरीका "मार्शलिंग" है। दूसरे शब्दों में, उस ऑब्जेक्ट को एक कैरेक्टर स्ट्रीम में बदल दें जिसे एक ऐसी फाइल में लिखा जा सकता है जिसे आप उसी ऑब्जेक्ट को प्राप्त करने के लिए बाद में "अनमैर्सल" या "अनसेरिज़ल" कर सकते हैं। किसी भी वस्तु की गहरी प्रतिलिपि प्राप्त करने के लिए इसका फायदा उठाया जा सकता है।
a = [[१,२]]
b = Marshal.load (Marshal.dump (a))
एक [0] << 3
b.inspect डालता है
यहाँ क्या हुआ है? Marshal.dump में संग्रहीत नेस्टेड सरणी का "डंप" बनाता है ए. यह डंप एक बाइनरी कैरेक्टर स्ट्रिंग है जिसे एक फाइल में स्टोर करने का इरादा है। इसमें सरणी की पूरी सामग्री, एक पूरी गहरी प्रतिलिपि है। आगे, Marshal.load इसके विपरीत करता है। यह इस द्विआधारी चरित्र सरणी को पार्स करता है और पूरी तरह से नए ऐरे तत्वों के साथ एक पूरी तरह से नया एरे बनाता है।
लेकिन यह एक ट्रिक है। यह अक्षम है, यह सभी वस्तुओं पर काम नहीं करेगा (यदि आप इस तरह से नेटवर्क कनेक्शन को क्लोन करने की कोशिश करते हैं तो क्या होता है?) और यह शायद बहुत तेज़ नहीं है। हालांकि, यह कस्टम की गहरी प्रतियों को कम करने का सबसे आसान तरीका है initialize_copy या क्लोन तरीकों। साथ ही, इसी तरह की विधियों के साथ किया जा सकता है to_yaml या to_xml यदि आपके पास उन्हें समर्थन देने के लिए पुस्तकालय लोड हैं।