perl

2012-08-15 44 views
5

में एक शर्त के रूप में एक स्केलर का उपयोग करना पहला टाइमर ... तो मुझे बताएं कि क्या कोई ऐसा प्रश्न है जिसे मैंने कोई सवाल उठाने पर ध्यान नहीं दिया है।perl

सवाल यह है कि एक स्थिति के रूप में एक स्केलर का उपयोग कैसे करें, क्योंकि नीचे दिया गया कोड काम नहीं करता है।

my @parameter=('hub'); 

my %condition; 
$condition{'hub'}{'1'}='$degree>=5'; 

foreach (@parameter) { 
     if ($condition{$_}{'1'}) {..} 
} 

मैंने सोचा कि ऐसा इसलिए है क्योंकि स्थिति का सही ढंग से व्याख्या नहीं किया गया है, इसलिए मैंने निम्नलिखित भी कोशिश की, जो काम नहीं किया।

if ("$condition{$parameter}{'1'}") { ..} 

वास्तव में किसी भी मदद की सराहना करेंगे। :)

+0

क्या आपका मतलब $ शर्त {'हब'} {'1'} = '$ डिग्री => 5' है; ? – squiguy

उत्तर

11

आप या तो स्ट्रिंग eval, जो पर्ल कोड के रूप में एक स्ट्रिंग

if (eval $condition{$_}{'1'}) { ... 

या शायद एक अधिक सुरक्षित दृष्टिकोण code references

का उपयोग करेंगे मूल्यांकन करता है चाहता हूँ
$condition{'hub'}{'1'} = sub { return $degree>=5 }; 

if ($condition{$_}{'1'}->()) { ... 

दूसरे उदाहरण में, आप एक चर के लिए कोड का एक टुकड़ा संलग्न कर रहे हैं। $var->() वाक्यविन्यास कोड निष्पादित करता है और कोड के वापसी मूल्य पर मूल्यांकन करता है।

+3

अनामित सब यह करने के लिए * सही * तरीका है। :) – friedo

+0

eval काम करता है। $ शर्त {'हब'} {'1'} = उप {वापसी $ डिग्री> = 5}; मेरे लिए काम नहीं करता है क्योंकि चर के लिए चर को परिभाषित किया जाना चाहिए- मेरे चर कोड के बाद बाद में परिभाषित किए गए हैं। धन्यवाद :) – bioinformant

2

आप क्या उम्मीद कर रहे हैं? स्ट्रिंग मानों को true के रूप में व्याख्या किया जाता है जब वे अस्वीकार्य होते हैं।

[email protected]: ~ $ perl -e 'print "oops\n" if "false" ; ' 
oops 
[email protected]: ~ $ perl -e 'print "oops\n" if "" ; ' 
[email protected]: ~ $ perl -e 'print "oops\n" if "\$degree < 5" ;' 
oops 

आप गतिशील रूप से आपकी परिस्थितियों में कोड का मूल्यांकन करना चाहते हैं, तो आप eval जांच करने के लिए किया है। उदाहरण:

my @conds=('$foo>42', '$foo>23'); 
my $foo = 33; 

foreach my $cond(@conds) { 
    print "$cond itself was true\n" if $cond; 
    print "$cond evaluated to true\n" if eval($cond); 
} 

प्रिंट

$foo>42 itself was true 
$foo>23 itself was true 
$foo>23 evaluated to true 
+2

'eval' ऐसा करने का गलत तरीका है। – friedo

+0

हां, तारों में कोड संग्रह करना बुरा है। – themel

+1

जबकि 'eval' के बारे में सावधानी बरतनी है, यह हमेशा "गलत तरीका" नहीं है। कभी-कभी सबसे तेज़, आसान तरीका ठीक है। प्रत्येक पर्ल स्क्रिप्ट अंतरिक्ष स्टेशन पर जीवन समर्थन को संभालने या रोबोटिक सर्जन के स्केलपेल का मार्गदर्शन करने वाला नहीं है। – dan1111

4

जो आप करने का प्रयास कर रहे हैं वह वास्तविक कोड के रूप में '$ डिग्री> = 5' का मूल्यांकन करना है। कोड के रूप में स्ट्रिंग का मूल्यांकन करने की कोशिश करने के बजाय (जिसे eval के साथ किया जा सकता है), यह आमतौर पर एक कोड-संदर्भ पास करने के लिए सुरक्षित और अक्सर अधिक मजबूत होता है। तुम्हें पता है, मांग पर सशर्त बाद के चरणों उत्पन्न करने के लिए इस तरह एक जनरेटर सबरूटीन उपयोग कर सकते हैं:

sub generate_condition { 
    my ($test, $bound) = @_; 
    return sub { return $test >= $bound; }; 
} 

my %condition; 
$condition{'hub'}{'1'} = generate_condition($degree, 5); 

if($condition{$parameter}{1}->()) { ... } 

यह एक छोटे से अधिक मुश्किल हो जाता है आप >= (यानी, रिश्ते ही) गतिशील रूप में अच्छी तरह से बनाया जा करना चाहते हैं। फिर आपके पास कुछ विकल्प हैं। कोई आपको अपने सभी जोखिमों के साथ स्ट्रिंग eval पर वापस ले जाता है (विशेष रूप से यदि आप अपने उपयोगकर्ता को स्ट्रिंग निर्दिष्ट करना शुरू करते हैं)। दूसरा generate_condition() उप के भीतर एक लुकअप टेबल होगा।

generate_condition() एक subroutine संदर्भ देता है जो लागू होने पर, सृजन के समय में स्थित स्थिति का मूल्यांकन करेगा।

यहां एक सामान्यीकृत समाधान है जो किसी भी पर्ल की सशर्तताओं को स्वीकार करेगा और उन्हें सबराउटिन में परीक्षण किए गए तर्कों के साथ लपेट देगा। subref तो सशर्त मूल्यांकन करने के लिए लागू किया जा सकता है:

use strict; 
use warnings; 
use feature qw/state/; 

sub generate_condition { 
    my ($test, $relation, $bound) = @_; 
    die "Bad relationship\n" 
     if ! $relation =~ m/^(?:<=?|>=?|==|l[te]|g[te]|cmp)$/; 
    state $relationships = { 
     '<'  => sub { return $test < $bound }, 
     '<=' => sub { return $test <= $bound }, 
     '==' => sub { return $test == $bound }, 
     '>=' => sub { return $test >= $bound }, 
     '>'  => sub { return $test > $bound }, 
     '<=>' => sub { return $test <=> $bound }, 
     'lt' => sub { return $test lt $bound }, 
     'le' => sub { return $test le $bound }, 
     'eq' => sub { return $test eq $bound }, 
     'ge' => sub { return $test ge $bound }, 
     'gt' => sub { return $test gt $bound }, 
     'cmp' => sub { return $test cmp $bound }, 
    }; 
    return $relationships->{$relation}; 
} 


my $true_condition = generate_condition(10, '>', 5); 
my $false_condition = generate_condition('flower', 'eq', 'stamp'); 

print '10 is greater than 5: ', 
     $true_condition->() ? "true\n" : "false\n"; 
print '"flower" is equal to "stamp": ', 
     $false_condition->() ? "true\n" : "false\n"; 

अक्सर जब आप चीजों को एक कॉल-समय के बजाय सबरूटीन निर्माण समय पर बाध्य करने के लिए एक पैरामीटर खुला छोड़ में रुचि रखता है के इन प्रकार के निर्माण।आइए मान लें कि आप केवल "$bound" और "$ relation" पैरामीटर को बांधना चाहते हैं, लेकिन subroutine कॉल समय पर विनिर्देश के लिए "$test" खोलें। आप इस तरह अपने उप पीढ़ी को संशोधित करेगा:

sub generate_condition { 
    my ($relation, $bound) = @_; 
    die "Bad relationship\n" 
     if ! $relation =~ m/^(?:<=?|>=?|==|l[te]|g[te]|cmp)$/; 
    state $relationships = { 
     '<'  => sub { return $_[0] < $bound }, 
     # ...... 

और फिर इस तरह यह आह्वान:

my $condition = generate_condition('<', 5); 
if($condition->(2)) { 
    print "Yes, 2 is less than 5\n"; 
} 

लक्ष्य रिलेशनल मूल्यांकन में दोनों बाईं और दाईं ओर की लेट बाइंडिंग प्रदान करने के लिए है, तो इस काम करेगा:

sub generate_condition { 
    my $relation = shift; 
    die "Bad relationship\n" 
     if ! $relation =~ m/^(?:<=?|>=?|==|l[te]|g[te]|cmp)$/; 
    state $relationships = { 
     '<'  => sub { return $_[0] < $_[1] }, 
     '<=' => sub { return $_[0] <= $_[1] }, 
     # ...... and so on ..... 
    return $relationship->($relation); 
} 

my $condition = generate_condition('<'); 
if($condition->(2,10)) { print "True.\n"; } 

उपकरण इस तरह की कार्यात्मक प्रोग्रामिंग की श्रेणी में आता है, और मार्क जेसन डोमिनस की किताबमें सुंदर विस्तार से कवर किया जाता है

+0

आपके पहले कोड ब्लॉक में समस्याएं हैं: http://pastie.org/4515233 - \ $ डिग्री/$$ परीक्षण का उपयोग करना चाहिए। – themel

+0

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

+0

एह, ठीक है, लेकिन यह थोड़ा सा व्यर्थ लगता है - वापसी मूल्य स्थिर होने पर हर बार स्थिति का मूल्यांकन क्यों करें? – themel