2017-12-08 28 views
5
sub foo { 
    my @return_value = (1, 2); 
} 
my @receiver = foo(); 

क्या यह असाइनिंग किसी अन्य असाइनिंग की तरह है? सरणी स्मृति में डुप्लिकेट है? मुझे इस कारण पर संदेह है क्योंकि सबराउटिन द्वारा धारित सरणी डिस्पोजेबल है, एक नकल पूरी तरह से अनावश्यक है। अनुकूलन कारण के लिए @receiver को सरणी को 'लिंक' करने का अर्थ है।पर्ल में, एक चर के लिए एक subroutine के वापसी मूल्य असाइन करते समय, स्मृति में डुप्लिकेट डेटा है?

वैसे, मैंने एक समान प्रश्न Perl: function returns reference or copy? देखा लेकिन मुझे जो चाहिए वह नहीं मिला।

और मैं पर्ल 5

ps के बारे में बात कर रहा हूं। perl के बारे में इस तरह के विषयों पर कोई किताबें या सामग्री?

उत्तर

3

यदि आप एक स्पष्ट वापसी निर्दिष्ट नहीं करते हैं तो सबराउटिन अंतिम ऑपरेशन का परिणाम देता है।

@return_value@receiver से अलग से बनाई गई है और मूल्यों कॉपी कर रहे हैं और जब यह सबरूटीन निकास पर दायरे से बाहर चला जाता है @return_value द्वारा प्रयुक्त स्मृति जारी किया गया है।

तो हाँ - उपयोग की गई स्मृति डुप्लीकेट है।

आप सख्त इस से बचना चाहते हैं, तो आप एक गुमनाम सरणी एक बार 'पास' के आसपास के लिए एक संदर्भ बना सकते हैं और:

#!/usr/bin/env perl 
use strict; 
use warnings; 

use Data::Dumper; 

sub foo { 
    my $anon_array_ref = [ 1, 2 ]; 
    return $anon_array_ref; 
} 

my $results_from_foo = foo(); 

print Dumper $results_from_foo; 

यह आमतौर पर समय से पहले अनुकूलन हालांकि हो जाएगा, जब तक कि आप क्या आप जानते हैं ' वास्तव में बड़े डेटा संरचनाओं से निपट रहे हैं।

नोट - असाइनमेंट के बाद आपको अपने उप में एक स्पष्ट return; शामिल करना चाहिए, क्योंकि यह स्पष्ट करने का अच्छा अभ्यास है कि आप क्या कर रहे हैं।

+0

* "आपको शायद एक स्पष्ट 'वापसी'" * 'वापसी 'गैर-पर्ल भाषाओं के लिए शामिल होना चाहिए! मुझे लगता है कि यह सबराउटिन के अंतिम विवरण में वापस आने वाली सूची का मूल्यांकन करने के लिए स्पष्ट (और briefer) है। पुराने perls में यह चीजों को 'रिटर्न' जोड़ने के लिए धीमा कर देता है, और हमें 'वापसी 1;' – Borodin

+3

'मॉड्यूल के अंत में' लर्निंग पर्ल (6 वां) पुस्तक 'के बजाय मॉड्यूल के अंत में' 1 ~ 'रखने में प्रसन्नता हो रही है। 74': _Some प्रोग्रामर प्रत्येक बार वापसी मूल्य का उपयोग करना पसंद करते हैं, दस्तावेज के साधन के रूप में कि यह एक वापसी मूल्य है। आपको वास्तव में इसकी आवश्यकता नहीं है, लेकिन इससे कुछ भी नुकसान नहीं पहुंचाता है। हालांकि, कई पर्ल प्रोग्रामर मानते हैं कि यह टाइपिंग के अतिरिक्त सात वर्ण हैं ._ :) मुझे पर्ल किताबें पसंद हैं। :) – jm666

6

:lvalue सबस द्वारा लौटाए गए स्केलर्स की प्रतिलिपि नहीं बनाई गई है।

एक्सएस सबस द्वारा लौटाए गए स्केलर की प्रतिलिपि नहीं बनाई गई है।

फ़ंक्शन (नामित ऑपरेटर) द्वारा दिए गए स्केलर की प्रतिलिपि नहीं बनाई गई है।

अन्य subs द्वारा लौटाए गए स्केलर की प्रतिलिपि बनाई गई है।

लेकिन किसी भी असाइनमेंट में खेलने से पहले यह है। यदि आप लौटाए गए मानों को एक चर में आवंटित करते हैं, तो आप उन्हें कॉपी करेंगे (फिर, सामान्य पर्ल उप के मामले में)।

इसका मतलब है my $y = sub { $x }->(); प्रतियां $x प्रतियां!

लेकिन यह अनुकूलन के कारण वास्तव में कोई फर्क नहीं पड़ता।


चलो एक उदाहरण के साथ शुरू करते हैं जब उनकी प्रतिलिपि नहीं बनाई जाती है।

$ perl -le' 
    sub f :lvalue { my $x = 123; print \$x; $x } 
    my $r = \f(); 
    print $r; 
' 
SCALAR(0x465eb48) # $x 
SCALAR(0x465eb48) # The scalar on the stack 

लेकिन आप :lvalue ...

$ perl -le' 
    sub f { my $x = 123; print \$x; $x } 
    my $r = \f(); 
    print $r; 
' 
SCALAR(0x17d0918) # $x 
SCALAR(0x17b1ec0) # The scalar on the stack 

इससे भी बदतर, एक आम तौर पर एक चर को अदिश बताए, तो एक दूसरे की नकल होती है द्वारा इस प्रकार को दूर करता है, तो।

$ perl -le' 
    sub f { my $x = 123; print \$x; $x } 
    my $r = \f(); # \ 
    print $r;  # > my $y = f(); 
    my $y = $$r; #/
    print \$y; 
' 
SCALAR(0x1802958) # $x 
SCALAR(0x17e3eb0) # The scalar on the stack 
SCALAR(0x18028f8) # $y 

प्लस तरफ, तारों की प्रतिलिपि बनाने की लागत को कम करने के लिए अनुकूलित में असाइनमेंट।

एक्सएस सब और फ़ंक्शन (नामित ऑपरेटर) आमतौर पर प्राणघातक ("टेम्प") स्केलर लौटाते हैं। ये मौत की पंक्ति पर "निशान" हैं। यदि उनके संदर्भ में दावा करने के लिए कुछ भी कदम नहीं उठाए जाएंगे तो वे स्वचालित रूप से नष्ट हो जाएंगे।

पर्ल (< 5.20) के पुराने संस्करणों में, किसी अन्य स्केलर को एक प्राणघातक स्ट्रिंग असाइन करने से स्ट्रिंग बफर की प्रतिलिपि बनाने से बचने के लिए स्ट्रिंग बफर को स्वामित्व में स्थानांतरित किया जाएगा। उदाहरण के लिए, my $y = lc($x);lc द्वारा बनाई गई स्ट्रिंग की प्रतिलिपि नहीं करता है; बस स्ट्रिंग सूचक की प्रतिलिपि बनाई गई है।

$ perl -MDevel::Peek -e'my $s = "abc"; Dump($s); $s = lc($s); Dump($s);' 
SV = PV(0x1705840) at 0x1723768 
    REFCNT = 1 
    FLAGS = (PADMY,POK,IsCOW,pPOK) 
    PV = 0x172d4c0 "abc"\0 
    CUR = 3 
    LEN = 10 
    COW_REFCNT = 1 
SV = PV(0x1705840) at 0x1723768 
    REFCNT = 1 
    FLAGS = (PADMY,POK,pPOK) 
    PV = 0x1730070 "abc"\0  <-- Note the change of address from stealing 
    CUR = 3      the buffer from the scalar returned by lc. 
    LEN = 10 

पर्ल के नए संस्करण (≥ 5.20) में, असाइनमेंट ऑपरेटर कभी नहीं [1] प्रतियां स्ट्रिंग बफर। इसके बजाए, पर्ल के नए संस्करण एक कॉपी-ऑन-राइट ("गाय") तंत्र का उपयोग करते हैं।

$ perl -MDevel::Peek -e'my $x = "abc"; my $y = $x; Dump($x); Dump($y);' 
SV = PV(0x26b0530) at 0x26ce230 
    REFCNT = 1 
    FLAGS = (POK,IsCOW,pPOK) 
    PV = 0x26d68a0 "abc"\0   <----+ 
    CUR = 3        | 
    LEN = 10        | 
    COW_REFCNT = 2       +-- Same buffer (0x26d68a0) 
SV = PV(0x26b05c0) at 0x26ce248   | 
    REFCNT = 1        | 
    FLAGS = (POK,IsCOW,pPOK)    | 
    PV = 0x26d68a0 "abc"\0   <----+ 
    CUR = 3 
    LEN = 10 
    COW_REFCNT = 2 

ठीक है, अब तक, मैं केवल scalars के बारे में बात की है। खैर, ऐसा इसलिए है क्योंकि subs और फ़ंक्शंस केवल स्केलर [2] लौटा सकते हैं।

अपने उदाहरण में, अदिश @return_value करने के लिए सौंपा लौटा दिया जाएगा [3], की नकल की है, तो दूसरी बार @receiver में काम से कॉपी किया गया।

आप सरणी के संदर्भ को वापस कर इन सब से बच सकते हैं।

sub f { my @fizbobs = ...; \@fizbobs } 
my $fizbobs = f(); 

केवल एक चीज की नकल की एक संदर्भ, सरल गैर अपरिभाषित अदिश है।


  1. ठीक है, शायद कभी नहीं नहीं। मुझे लगता है कि गाय गिनती को पकड़ने के लिए स्ट्रिंग बफर में एक फ्री बाइट होना आवश्यक है।

  2. सूची संदर्भ में, वे 0, 1 या उनमें से कई को वापस कर सकते हैं, लेकिन वे केवल स्केलर लौटा सकते हैं।

  3. आपके उप का अंतिम ऑपरेटर एक सूची असाइनमेंट ऑपरेटर है। सूची संदर्भ में, सूची असाइनमेंट ऑपरेटर स्केलर देता है जिस पर इसके बाएं हाथ की तरफ (एलएचएस) मूल्यांकन होता है। अधिक जानकारी के लिए Scalar vs List Assignment Operator देखें।

+3

तो, यह एक ऐसा उत्तर है जो मुझे आश्वासन देता है कि मैं ** ** ** को बिल्कुल नहीं जानता (अभी तक)।:) होवेवर, मुझे यह पसंद है कि यहां ऐसे उत्तर हैं क्योंकि वे मुझे गहरी चीजों को समझने में मदद कर सकते हैं (कुछ साल बाद) :) – kobame

+1

@amon, ढेर में एवी हो सकता है (उदाहरण के लिए 'पुश' स्टैक पर पहली वस्तु की अपेक्षा करता है एक एवी हो), लेकिन subs उन्हें वापस नहीं कर सकते हैं। '@ रिसीवर' और' @ return_value' एक ही सरणी नहीं हैं, कम से कम अतिरिक्त काम के बिना नहीं: 'perl -e'use सुविधा qw (decl_refs refaliasing कहना); मेरा \ @ ए = सब {मेरा @ ए; कहें \ @ ए; \ @a} ->(); \ @a; ''कहें। – ikegami

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