2012-08-15 11 views
5

最初のタイマー...質問をしている間に注意を払わなかったことがあれば教えてください。perlの条件としてスカラーを使用する

質問は以下のコードが機能しないため、条件としてスカラーを使用する方法です。

条件が正しく解釈されないと考えていたので、以下のことも試みましたが、これもうまくいきませんでした。

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

本当に助けていただければ幸いです。 :)

+0

あなたは$ condition {'hub'} {'1'} = '$ degree => 5'を意味しますか? ? – squiguy

答えて

11

あなたのどちらかがPerlコード

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

またはおそらくより安全なアプローチがcode references

を使用されるような文字列を評価し、文字列のevalを、したいです
$condition{'hub'}{'1'} = sub { return $degree>=5 }; 

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

2番目の例では、コードを変数に付加しています。 $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」についての注意が必要ですが、必ずしも「間違った方法」であるとは限りません。場合によっては、最も速く、最も簡単な方法でも問題ありません。すべてのPerlスクリプトが、宇宙ステーションでの生命維持を支援したり、ロボット外科医のメスを案内したりするわけではありません。 – 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}->()) { ... } 

あなたは>=(すなわち、関係自体が)、動的にも作成したい場合には、もう少しトリッキー取得します。次に、いくつかの選択肢があります。 1つは、すべてのリスクを伴うstringy evalに戻ります(特に、ユーザーが文字列を指定できるようにする場合)。もう1つはgenerate_condition() sub内のルックアップテーブルです。

generate_condition()は、呼び出されると、作成時にバインドされた条件を評価するサブルーチン参照を返します。

ここには、Perlの条件を受け入れ、テストされる引数とともにサブルーチンにラップする一般的なソリューションがあります。 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"; 

使用すると、1つの呼び出し時にバインドするのではなく、サブルーチンの製造時にに開いつのパラメータを残すことに興味ある物事のこれらの種類を構築します。たとえば、 "$bound"と "$ relation"パラメータをバインドし、サブルーチンコール時に "$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 - \ $ degree/$$ testを使用してください。 – themel

+0

あなたはそれを間違って使用しています。それは、サブが製造された後、$度を見るはずではありません。条件subが生成された時点で$ degreeと$ testをロックすることを意図しています。 $ degreeを更新できるようにするには、新しいサブ(新しい値がバインドされている)を生成するか、匿名サブが呼び出されるまで試行値を空けることができる2番目のコードスニペットを使用する必要があります。 – DavidO

+0

ええ、大丈夫ですが、ちょっと意味がないようです - 戻り値が一定であるたびに条件を評価するのはなぜですか? – themel

関連する問題