2010-06-03 11 views
7

निम्न पर्ल कोड पर विचार करें।पर्ल, स्ट्रिंग आलसी

#!/usr/bin/perl 

use strict; 
use warnings; 

$b="1"; 

my $a="${b}"; 

$b="2"; 

print $a; 

स्क्रिप्ट स्पष्ट रूप से 1 आउटपुट करता है। मैं यह चाहता हूं कि $b का वर्तमान मूल्य जो भी हो।

इस तरह आलसी मूल्यांकन प्राप्त करने के लिए पर्ल में सबसे बढ़िया तरीका क्या होगा? $a की आवश्यकता होने तक मुझे ${b} "अपरिवर्तित" रहने के लिए चाहिए।

+0

मैं इस तरह के उदाहरणों के लिए '$ a' और' $ b' का उपयोग न करने का सुझाव दूंगा, क्योंकि ये perl विशेष हैं और * नहीं * lexically scoped (जैसा कि 'my' के सामने 'my' के आपके चूक से प्रमाणित है बी उदाहरण के लिए)। तकनीकों के अच्छे चयन के लिए – pilcrow

उत्तर

15

के लिए एक संदर्भ मैं जानते हुए भी तुम क्यों ऐसा करना चाहते हैं में अधिक रुचि रखते हूँ। आपको वास्तव में क्या करना है इसके आधार पर आप विभिन्न दृष्टिकोणों का उपयोग कर सकते हैं।

आप एक coderef में कोड लपेट सकता है, और केवल यह मूल्यांकन जब आपको उसकी आवश्यकता:

use strict; use warnings; 

my $b = '1'; 
my $a = sub { $b }; 
$b = '2'; 
print $a->(); 

इस का एक प्रकार (एक closure के रूप में एक नामित समारोह का उपयोग करने के यह शायद सबसे अच्छा है होगा दृष्टिकोण, अपने बुला कोड की व्यापक संदर्भ) में:

my $b = '1'; 
sub print_b 
{ 
    print $b; 
} 

$b = '2'; 
print_b(); 

आप और मूल चर के लिए एक संदर्भ इस्तेमाल कर सकते हैं, यह भिन्नता की जरूरत के रूप में:

my $b = '1'; 
my $a = \$b; 
$b = '2'; 
print $$a; 
+1

+1, लेकिन आपके दूसरे सबराउटिन के लिए काम करने के लिए, आपको subroutine को परिभाषित करने से पहले 'मेरा $ b' परिभाषित करने की आवश्यकता है, अन्यथा यह इसके बजाय वैश्विक $ b से जुड़ा हुआ है। –

+0

@ एंडी: अच्छा बिंदु! – Ether

+0

मैं एक त्वरित और गंदे स्ट्रिंग विकल्प करने के तरीके के साथ आने की कोशिश कर रहा था। आपका कोडफ्र सुझाव बहुत अच्छा था, धन्यवाद – Mike

4

कोड चलने पर पर्ल एक स्ट्रिंग को इंटरपोलेट करेगा, और मुझे ऐसा करने के तरीके के बारे में पता नहीं है, प्रारूपों से कम (जो बदसूरत आईएमओ हैं)। तुम कर सकते हो क्या, हालांकि, परिवर्तन "जब कोड रन" कुछ और अधिक सुविधाजनक करने के लिए, एक उप में स्ट्रिंग लपेटकर और यह बुला जब आप स्ट्रिंग अंतर्वेशित जरूरत से ...

$b = "1"; 
my $a = sub { "\$b is $b" }; 
$b = "2"; 
print &$a; 

या, आप कर सकते थे है कुछ eval जादू करो, लेकिन यह थोड़ा और घुसपैठ कर रहा है (इसे प्राप्त करने के लिए आपको स्ट्रिंग के कुछ हेरफेर करने की आवश्यकता होगी)।

1

आप यह दावा करना चाहते हैं कि $ एक का उपयोग किया जाता है जब इसका मूल्यांकन किया जाता है ... आप केवल ऐसा कर सकते हैं यदि $ वास्तव में एक स्केलर नहीं है, तो यह एक कार्य (सीएचओओ का जवाब) हो सकता है या , इस सरल मामले में, अन्य चर

my $b="1"; 
my $a= \$b; 
$b="2"; 
print $$a; 
3

जो आप चाहते हैं वह आलसी मूल्यांकन नहीं है, लेकिन देर से बाध्यकारी। इसे पर्ल में प्राप्त करने के लिए, आपको eval का उपयोग करने की आवश्यकता है।

my $number = 3; 
my $val = ""; 

my $x = '$val="${number}"'; 

$number = 42; 

eval $x; 

print "val is now $val\n"; 

ध्यान दें कि eval आमतौर पर अक्षम के साथ-साथ विधिपूर्वक नृशंस है। आप अन्य उत्तरों में से एक से समाधान का उपयोग कर लगभग निश्चित रूप से बेहतर हैं।

3

जैसा कि अन्य ने उल्लेख किया है, पर्ल केवल स्ट्रिंग का मूल्यांकन करेगा क्योंकि आपने रनटाइम पर कंपाइलर को आमंत्रित करने के लिए eval का उपयोग करके उन्हें लिखा है। आप कुछ अन्य उत्तरों में उल्लिखित संदर्भों का उपयोग कर सकते हैं, लेकिन यह कोड के तरीके को बदलता है ($$a बनाम $a)। हालांकि, यह पर्ल है, tie का उपयोग कर, एक साधारण चर के पीछे उन्नत कार्यक्षमता को छिपाने का एक तरीका है।

{package Lazy; 
    sub TIESCALAR {bless \$_[1]}   # store a reference to $b 
    sub FETCH {${$_[0]}}     # dereference $b 
    sub STORE {${$_[0]} = $_[1]}   # dereference $b and assign to it 
    sub new {tie $_[1] => $_[0], $_[2]} # syntactic sugar 
} 

my $b = 1; 
Lazy->new(my $a => $b); # '=>' or ',' but not '=' 

print "$a\n"; # prints 1 
$b = 2; 
print "$a\n"; # prints 2 

आप tie के लिए दस्तावेज़ देखने सकते हैं, लेकिन संक्षेप में, यह आप एक चर के अपने खुद के कार्यान्वयन (scalars के लिए, सारणी, हैश, या फ़ाइल संभालती) को परिभाषित करने की अनुमति देता है।तो यह कोड नए चरको कार्यान्वयन के साथ बनाता है जो $b के वर्तमान मान को प्राप्त या सेट करता है ($b आंतरिक रूप से संदर्भ संग्रहीत करके)। new विधि की सख्ती से आवश्यकता नहीं है (कन्स्ट्रक्टर वास्तव में TIESCALAR है) लेकिन सीधे कॉलिंग कोड में tie का उपयोग करने से बचने के लिए सिंटैक्टिक चीनी के रूप में प्रदान किया जाता है।

(tie my $a, 'Lazy', $b; होगा जो)

1

मैं $ चाहते हैं {b} "unreplaced" रहने के लिए जब तक $ एक की जरूरत है।

फिर मैं sprintf का उपयोग करके स्ट्रिंग इंटरपोलेशन eschewing की सिफारिश करता हूं, ताकि जब आवश्यक हो तो आप "इंटरपोलेट" करें। अधिक विदेशी प्रारूप विनिर्देशक साथ

use strict; 
use warnings; 

package LazySprintf; 

# oh, yuck 
sub TIESCALAR { my $class = shift; bless \@_, $class; } 
sub FETCH  { my $self = shift; sprintf $self->[0], @$self[1..$#$self]; } 

package main; 

my $var = "foo"; 
tie my $lazy, 'LazySprintf', '%s', $var; 

print "$lazy\n"; # prints "foo\n" 
$var = "bar"; 
print "$lazy\n"; # prints "bar\n"; 

काम करता है, भी:

बेशक, इस आधार पर आप एक साथ कुछ त्वरित (ish) और गंदे tie सकता है। छी।

+0

पूरी तरह से कमाल 'यक' :-) –