5

初めてのタイマー...質問をする際に注意を払っていないことがあれば教えてください。

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

my @parameter=('hub');

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

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

条件が正しく解釈されていないためだと思ったので、次のことも試しましたが、これもうまくいきませんでした。

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

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

4

3 に答える 3

11

文字列を Perl コードとして評価する文字列 eval が必要な場合

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

または、より安全なアプローチは、コード参照を使用することです

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

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

2 番目の例では、コードの一部を変数にアタッチしています。$var->()構文はコードを実行し、コードの戻り値に評価されます。

于 2012-08-15T19:50:27.130 に答える
4

あなたがしようとしているのは、'$degree>=5' を実際のコードとして評価することです。文字列をコードとして評価しようとする (これはevalで実行できます) よりも、代わりにコード参照を渡す方が通常は安全で、多くの場合より堅牢です。次のように、generator サブルーチンを使用して、オンデマンドで条件付きサブルーチンを生成できます。

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に戻ります(特に、ユーザーに文字列を指定させ始めた場合)。generate_condition()もう 1 つは、サブ内のルックアップ テーブルです。

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"; }

この種のツールは関数型プログラミングのカテゴリに分類され、Mark Jason Dominus の著書Higher Order Perlで美しく詳細に説明されています。

于 2012-08-15T19:52:30.197 に答える
2

何を期待していますか?文字列値はtrue、空でない場合と解釈されます。

themel@kallisti: ~ $ perl -e 'print "oops\n" if "false" ; '
oops
themel@kallisti: ~ $ perl -e 'print "oops\n" if "" ; '
themel@kallisti: ~ $ 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
于 2012-08-15T19:50:15.000 に答える