2016-01-06 4 views
6

आइए कहें कि मेरे पास एक बड़ा हैश है और मैं इसकी सामग्री की सामग्री पर पुन: प्रयास करना चाहता हूं। मानक मुहावरा कुछ इस तरह होगा:क्या हैश संदर्भ पर पुनरावृत्त करने के लिए इसे पूरी तरह से perl में कॉपी करना आवश्यक है?

while(($key, $value) = each(%{$hash_ref})){ 
    ///do something 
} 

हालांकि, अगर मैं समझता हूँ कि मेरी पर्ल सही ढंग से यह वास्तव में दो बातें कर रही है। सबसे पहले

%{$hash_ref} 

सूची संदर्भ में रेफरी का अनुवाद कर रहा है। इस प्रकार

(key1, value1, key2, value2, key3, value3 etc) 

जैसे कुछ लौटने पर मेरी स्टैक्स मेमोरी में संग्रहीत किया जाएगा। फिर प्रत्येक विधि चल जाएगी, स्मृति में पहले दो मानों को खाएं (key1 & value1) और प्रक्रिया के लिए उन्हें मेरे समय लूप पर लौटाना।

यदि मेरी समझ यह सही है कि इसका मतलब है कि मैंने अपने पूरे हैश को मेरी स्टैक्स मेमोरी में प्रभावी रूप से प्रतिलिपि बनाई है, तो केवल नई प्रतिलिपि को फिर से चालू करने के लिए, जो कि बड़े हैश के लिए महंगा हो सकता है, क्योंकि इसे फिर से शुरू करने की कीमत के कारण सरणी दो बार, लेकिन संभावित कैश हिट के कारण भी अगर दोनों हैंश को स्मृति में एक बार में नहीं रखा जा सकता है। यह बहुत अक्षम लगता है। मैं सोच रहा हूं कि क्या वास्तव में ऐसा होता है, या यदि मैं या तो वास्तविक व्यवहार को गलत समझ रहा हूं या संकलक मेरे लिए अक्षमता को अनुकूलित करता है?

मान लें कि मैं मानक व्यवहार के बारे में सही हूं।

  1. क्या हैश की प्रतिलिपि से बचने के लिए हैश की प्रतिलिपि बनाने से बचने के लिए कोई वाक्यविन्यास है? यदि हैश के लिए नहीं है तो सरल सरणी के लिए कोई है?

  2. क्या इसका मतलब यह है कि उपर्युक्त उदाहरण में मैं अपने हैश की प्रति और मेरे वास्तविक हैश के बीच असंगत मूल्य प्राप्त कर सकता हूं यदि मैं अपने लूप के भीतर हैश_फ सामग्री को संशोधित करता हूं; जिसके परिणामस्वरूप $ वैल्यू एक अलग मूल्य है तो $ हैश_फ -> ($ कुंजी)?

+1

किसी संदर्भ को अस्वीकार करने से मूल डेटा की एक प्रति नहीं बनती है; जो पहले स्थान पर संदर्भों का उपयोग करने के उद्देश्य को हरा देगा। आप '$ foo = {% हैश}' के बारे में सोच रहे हैं, जो '% हैश' में डेटा की एक प्रति का उपयोग कर अज्ञात हैश बनाता है। – ThisSuitIsBlackNot

+1

ध्यान दें कि 'प्रत्येक' की तुलना में 'कुंजी' और' मानों 'का उपयोग करना अधिक आम है, क्योंकि अंतिम के साथ अंत में एक लूप को समाप्त करने में समस्याएं हो सकती हैं, और एक साथ दो स्थानों में एक हैश को फिर से चालू करना पड़ सकता है। – Borodin

+0

@ बोरोडिन इसका उल्लेख करने के लिए धन्यवाद। मैंने अनुमान लगाया था कि हैश में कुछ भी जोड़ना या निकालना खतरनाक होगा, लेकिन मैंने माना था कि पर्ल मुझे अन्यथा बचाएगा। मुझे एहसास नहीं हुआ था कि जब तक आप मुझे ऑनलाइन शोध करने के लिए प्रेरित नहीं करते तब तक यह फिर से प्रवेश नहीं किया गया था। हालांकि ऐसा लगता है कि कीज़ की कॉपीिंग समस्या है, मैं प्रत्येक – dsollen

उत्तर

1

कोई प्रतिलिपि each द्वारा बनाई गई है (हालांकि आप काम के माध्यम से $key और $value में लौटे मूल्यों नकल करते हैं)। हैश खुद को each पर भेज दिया गया है।

each थोड़ा खास है। यह निम्नलिखित वाक्यविन्यासों का समर्थन करता है:

each HASH 
each ARRAY 

जैसा कि आप देख सकते हैं, यह मनमाने ढंग से अभिव्यक्ति स्वीकार नहीं करता है। (यह each EXPR या each LIST होगा)। इसका कारण सूची संदर्भ में मूल्यांकन करने के बजाय हैश %foo को each पर पास करने के लिए each(%foo) को अनुमति देना है। each ऐसा कर सकता है क्योंकि यह एक ऑपरेटर है, और ऑपरेटरों के पास अपने स्वयं के पार्सिंग नियम हो सकते हैं। हालांकि, आप \% प्रोटोटाइप के साथ कुछ ऐसा कर सकते हैं।

use Data::Dumper; 

sub f  { print(Dumper(@_)); } 
sub g(\%) { print(Dumper(@_)); } # Similar to each 

my %h = (a=>1, b=>2); 
f(%h); # Evaluates %h in list context. 
print("\n"); 
g(%h); # Passes a reference to %h. 

आउटपुट:

$VAR1 = 'a';   # 4 args, the keys and values of the hash 
$VAR2 = 1; 
$VAR3 = 'b'; 
$VAR4 = 2; 

$VAR1 = {    # 1 arg, a reference to the hash 
      'a' => 1, 
      'b' => 2 
     }; 

%{$h_ref}, %h रूप में ही है तो ऊपर के सभी %{$h_ref} को भी लागू होता है।


ध्यान दें कि हैश की प्रतिलिपि बनाई गई है, भले ही हैश की प्रतिलिपि न हो। चाबियां "प्रतिलिपि बनाई गई हैं", लेकिन मान सीधे लौटाए जाते हैं।

use Data::Dumper; 
my %h = (abc=>"def", ghi=>"jkl"); 
print(Dumper(\%h)); 
$_ = uc($_) for %h; 
print(Dumper(\%h)); 

आउटपुट:

$VAR1 = { 
      'abc' => 'def', 
      'ghi' => 'jkl' 
     }; 
$VAR1 = { 
      'abc' => 'DEF', 
      'ghi' => 'JKL' 
     }; 

आप इस here के बारे में अधिक पढ़ सकते हैं।

+0

धन्यवाद। मुझे लगता है कि यह उपरोक्त एक बेहतर स्पष्टीकरण है क्योंकि यह बेहतर है कि वे संदर्भ क्यों सूचीबद्ध करते हैं, जिसे मैं बनने की उम्मीद नहीं करता था; हालांकि स्वीकार्य रूप से अगर मैंने सवाल से बेहतर पूछा था तो यह स्पष्ट हो सकता है कि मेरी भ्रम की वजह से प्रत्येक व्यक्ति सूची सूची लेने की उम्मीद कर रहा था। यद्यपि स्पष्ट करने के लिए, क्या आप कह रहे हैं कि प्रत्येक एक subroutine नहीं है? सूची संदर्भ से बचने की क्षमता तब पर्ल द्वारा लिखे गए ऑपरेटरों तक सख्ती से सीमित है? मुझे पता है कि मैं ऑपरेटरों को ओवरराइड कर सकता हूं, लेकिन केवल एक सबराउटिन के साथ जिसके लिए एक रेफरी या सूची संदर्भ सही है? – dsollen

+1

यह [perlfunc] (http://perldoc.perl.org/perlfunc.html) की पहली पंक्ति है: "* इस खंड में कार्य अभिव्यक्ति में शर्तों के रूप में कार्य कर सकते हैं। वे दो प्रमुख श्रेणियों में आते हैं: सूची ऑपरेटर और यूनरी ऑपरेटरों का नाम दिया। * "कुछ कार्यों को subs द्वारा दोहराया नहीं जा सकता है, कुछ प्रोटोटाइप के साथ subs से अलग नहीं हैं, और कुछ ऐसे हो सकते हैं जो सामान्य सब से अलग नहीं हैं, लेकिन सभी ऑपरेटरों के रूप में लागू किए जाते हैं। – ikegami

+1

नहीं, सबकुछ नियंत्रित कर सकता है कि उनके कॉलर्स प्रोटोटाइप के माध्यम से भी पार्स किए गए हैं (जैसा कि मैंने दिखाया है)। आप पार्सर का विस्तार करने के लिए 'cv_set_call_parser' जैसी सुविधाओं का भी उपयोग कर सकते हैं। उदाहरण के लिए, ['सिंटैक्स qw (लूप) का उपयोग करें; '] (http://search.cpan.org/perldoc?Syntax:: फीचर :: लूप) इसका उपयोग करता है। – ikegami

5

नहीं, आपके द्वारा उद्धृत वाक्यविन्यास एक प्रतिलिपि नहीं बनाता है।

यह अभिव्यक्ति:

%{$hash_ref} 

बिल्कुल के बराबर है:

%$hash_ref 

और $hash_ref अदिश चर संभालने वास्तव में एक हैश के लिए एक संदर्भ शामिल है, तो % जोड़ने पर सामने बस है संदर्भ को 'dereferencing' - यानी यह उस मान को हल करता है जो अंतर्निहित हैश का प्रतिनिधित्व करता है (वह बात जो $hash_ref इंगित कर रही थी)।

यदि आप each फ़ंक्शन के लिए दस्तावेज़ देखें, तो आप देखेंगे कि यह एक हैश को तर्क के रूप में उम्मीद करता है। मोर्चे पर % डालने का तरीका यह है कि जब आप हैशफ है तो आप हैश प्रदान करते हैं।

आप अपने खुद के सबरूटीन लिखा था और इस तरह से यह करने के लिए एक हैश पारित कर दिया है:

my_sub(%$hash_ref); 

फिर कुछ स्तर पर आप कह सकते हैं कि हैश किया गया 'की नकल की' था, सबरूटीन विशेष @_ सरणी के अंदर के बाद से हैश से सभी कुंजी/मूल्य जोड़े की एक सूची होगी। हालांकि, उस स्थिति में, @_ के तत्व वास्तव में कुंजी और मानों के लिए उपनाम हैं। यदि आप कुछ ऐसा करते हैं तो आपको वास्तव में एक प्रति प्राप्त होगी: my @args = @_

पर्ल का बिल्टिन each फ़ंक्शन प्रोटोटाइप '+' के साथ घोषित किया गया है जो अंतर्निहित डेटा संरचना के संदर्भ में प्रभावी रूप से हैश (या सरणी) तर्क को सहारा देता है।

एक तरफ, संस्करण 5.14 के साथ शुरू, each फ़ंक्शन एक हैश का संदर्भ भी ले सकता है। तो बजाय:

($key, $value) = each(%{$hash_ref}) 

आप बस कह सकते हैं:

($key, $value) = each($hash_ref) 
+0

मेरे पास था आपकी टिप्पणी के बारे में कोई जानकारी नहीं है "5.14 के रूप में ..." यह अच्छी चीजें है। मुझे रिलीज नोट्स पढ़ने का बेहतर काम करने की ज़रूरत है। – Hambone

+5

@ हैम्बोन 'प्रत्येक $ ref' को 5.14 में एक * प्रयोगात्मक * सुविधा के रूप में पेश किया गया था, बाद में संशोधन या हटाने के अधीन। 5.24 के रूप में * इसे हटा दिया जाएगा, क्योंकि यह काफी परेशानी साबित हुआ। इसकी जगह 'postderef' सुविधा है, जिसे 5.20 में प्रयोगात्मक के रूप में पेश किया गया है और 5.24 में गैर-प्रयोगात्मक (वाक्यविन्यास या व्यवहार में कोई बदलाव नहीं होने के कारण) के रूप में अपग्रेड किया गया है। – hobbs

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

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