2012-08-15 4 views
5

첫 번째 타이머 ... 질문 할 때주의를 기울이지 않은 것이 있으면 알려주세요.perl에서 조건으로 스칼라 사용

질문은 아래 코드가 작동하지 않으므로 조건으로 스칼라를 사용하는 방법입니다.

my @parameter=('hub'); 

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

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

조건이 올바르게 해석되지 않았기 때문에 생각 했으므로 다음도 시도했지만 작동하지 않았습니다.

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

정말 도움이 되시겠습니까? :)

+0

당신은 $ condition { 'hub'} { '1'} = '$ degree => 5'를 의미합니까? ? – squiguy

답변

11

당신 하나가 더 안전한 방법은 code references

을 사용하는 것입니다

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

혹은 펄 코드로 문자열을 평가 문자열 평가를 원하는에게

$condition{'hub'}{'1'} = sub { return $degree>=5 }; 

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

두 번째 예에서는 코드를 변수에 연결합니다. $var->() 구문은 코드를 실행하고 코드의 반환 값을 계산합니다.

+3

익명의 서브가 이것을하기위한 * 올바른 방법입니다. :) – friedo

+0

eval works. $ condition { 'hub'} { '1'} = sub {return $ degree> = 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

'$ degree> = 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}->()) { ... } 

그것은 좀 더 까다로운 얻는다 당신이 >= (즉, 관계 자체가) 동적으로도 생성 할 경우. 그런 다음 몇 가지 선택 사항이 있습니다. 하나는 stringy eval로 돌아가며 모든 위험을 감수해야합니다 (특히 사용자가 문자열을 지정하게하는 경우). 다른 하나는 generate_condition() 하위의 찾아보기 테이블입니다.

generate_condition()은 호출 될 때 생성시 바인딩 된 조건을 평가하는 서브 루틴 참조를 반환합니다.

다음은 Perl의 조건을 받아들이고 테스트 할 인수와 함께 서브 루틴으로 랩핑하는 일반화 된 솔루션입니다. 하위 참조는 다음 조건을 평가하기 위해 호출 할 수 있습니다

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"매개 변수 만 바인딩하고 서브 루틴 호출시에는 사양에 대해 "$test"을 열어두고 싶다고 가정 해 봅시다. ,

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

을 목표 관계형 평가 왼손과 오른쪽 측면 모두 런타임에 바인딩을 제공하는 경우 :

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

을 그리고 이런 식으로 호출 :이처럼 하위 세대를 수정할 것 이 작동합니다 :

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 - \ $ degree/$$ test를 사용해야합니다. – themel

+0

방금 ​​잘못 사용했습니다. 그것은 하위가 제조 된 후 $ 학위를 보지 않아도됩니다. condition sub가 생성 될 때 $ degree와 $ test를 잠 그려고합니다. $ degree를 업데이트 할 수있게하려면 새 하위 값 (새 값이 바인딩 됨)을 생성하거나 익명 하위가 호출 될 때까지 평가판 값을 무료로 유지할 수있는 두 번째 코드 스 니펫을 사용해야합니다. – DavidO

+0

어, 알았어,하지만 그건 약간 무의미 해 보입니다. 반환 값이 일정 할 때마다 조건을 평가하는 이유는 무엇입니까? – themel