使用标量作为perl中的条件

时间:2012-08-15 19:39:18

标签: perl if-statement conditional-statements scalar

第一个计时器...所以,如果有任何我在提出问题时没有注意的话,请告诉我。

问题是如何使用标量作为条件,因为下面的代码不起作用。

my @parameter=('hub');

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

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

我认为那是因为条件没有被正确解释,所以我也尝试了以下,但也没有用。

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

非常感谢任何帮助。 :)

3 个答案:

答案 0 :(得分:11)

您要么需要字符串eval,它会将字符串计算为Perl代码

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

或者更安全的方法可能是使用code references

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

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

在第二个示例中,您将一段代码附加到变量。 $var->()语法执行代码并计算代码的返回值。

答案 1 :(得分: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的条件,并将它们与被测试的参数一起包装到子例程中。然后可以调用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”参数,但在子例程调用时将“$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

中有详细介绍。

答案 2 :(得分: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