2009-09-23 32 views
5

(अनुवर्ती मेरे पहले प्रश्न के, Ruby: how can I copy a variable without pointing to the same object?)रूबी: मैं इस सरणी की प्रतिलिपि कैसे बना सकता हूं?

मैं एक .svg फाइल में कुछ प्रतिस्थापन बनाने के लिए एक सरल रूबी कार्यक्रम लिख रहा हूँ। पहला कदम फ़ाइल से जानकारी खींचना और इसे सरणी में रखना है। इस समारोह को हर बार डिस्क से फ़ाइल पढ़ने से रोकने के लिए, मैं ज्ञापन डिजाइन पैटर्न का उपयोग करने की कोशिश कर रहा हूं - पहले कॉल के बाद प्रत्येक कॉल पर कैश किए गए परिणाम का उपयोग करें।

ऐसा करने के लिए, मैं एक वैश्विक चर का उपयोग कर रहा हूं, जो फ़ंक्शन से पहले परिभाषित किया गया है। लेकिन भले ही मैं .dup स्थानीय वैरिएबल लौटने से पहले एक स्थानीय व्यक्ति के लिए परिवर्तनीय हूं, फिर भी यह फ़ंक्शन जो कॉल करता है वह अभी भी वैश्विक चर को संशोधित कर रहा है।

#memoize to keep from having to read original file on each pass 
$svg_filedata_cache = [] #the global variable 
def svg_filedata(filename) 
    if $svg_filedata_cache.empty? 
     File.open(filename, "r"){|f| $svg_filedata_cache = f.readlines} 
    end 
    svg_filedata_cache = $svg_filedata_cache.dup #try to copy it 
    return svg_filedata_cache #SHOULD point to a different object (but doesn't) 
end 

दो सवाल (या दोनों का जवाब):

  1. क्यों अन्य कार्यों, जिसमें लेने के लिए और संशोधित मूल्य यहाँ लौटे, भी प्रभावित करते हैं

    यहाँ मेरी वास्तविक कोड है वैश्विक चर, भले ही मैंने इसे कॉपी करने के लिए .dup का उपयोग किया?

  2. मैं रूबी के लिए नया हूं और मुझे यकीन है कि यह करने के लिए यह सबसे रूबीस्क्यू तरीका नहीं है (और मुझे वैश्विक वैरिएबल पसंद नहीं है)। क्या आप एक बेहतर रणनीति का सुझाव दे सकते हैं?
+0

पीएस मुझे एहसास है कि यह वास्तव में $ svg_filedata_cache [filename] होना चाहिए, विभिन्न फ़ाइल नामों का उपयोग करके फ़ंक्शन कॉल की अनुमति देने के लिए, लेकिन इस मामले में इसकी आवश्यकता नहीं है। –

+0

बीटीडब्ल्यू, वैश्विक और लौटे ऑब्जेक्ट्स में अलग ऑब्जेक्ट_आईडी है, मेरा मानना ​​है कि आप लौटे सरणी के अंदर तारों का जिक्र कर रहे हैं, है ना? – khelll

+0

@ खेल - हाँ, मैंने इस तथ्य पर मेरा बयान दिया कि मूल सरणी की सामग्री बदल दी जा रही थी। –

उत्तर

9

डुप्लीड सरणी को संशोधित करना मूल को प्रभावित नहीं करेगा। हालांकि सरणी के अंदर तारों में संशोधन वैश्विक स्तर पर दिखाई देंगे क्योंकि वैश्विक सरणी और डुप्लिकेट सरणी में अभी भी एक ही तारों के संदर्भ होते हैं (डुप्लिकेट गहरी प्रति नहीं करता है)।

तो या तो एक गहरी प्रतिलिपि करें (svg_filedata_cache = $svg_filedata_cache.map {|line| line.dup}) या तारों पर उत्परिवर्तन संचालन से बचें।

+1

मुझे एहसास नहीं हुआ कि सरणी में प्रत्येक स्ट्रिंग अपनी वस्तु थी! मुझे लगता है कि यह वास्तव में सच है कि "रूबी में सब कुछ एक वस्तु है।" :) –

6

कोड बढ़ाना एक सा:

$svg_filedata_cache = [] #the global variable 
def svg_filedata(filename) 
    # Use ||= for memoiziation 
    $svg_filedata_cache ||= File.open(filename, "r"){|f| $svg_filedata_cache = f.readlines} 
    $svg_filedata_cache.dup #shallow copying 
end 

अद्यतन: एक सरल चाल सामान्य रूप में गहरी नकल करना है:

def deep_copy(obj) 
    Marshal.load(Marshal.dump(obj)) 
end 
+0

तो || = का अर्थ है "यदि बाईं तरफ झूठा (खाली) है, तो दाएं तरफ का उपयोग करें?" –

+2

इसका मतलब है कि बाएं तरफ चर के दाहिने तरफ मान असाइन करें, यदि वह चर पहले से सेट नहीं है। – khelll

2

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

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