5

第一次……所以让我知道在提出问题时是否有任何我没有注意的地方。

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

my @parameter=('hub');

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

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

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

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

非常感谢任何帮助。:)

4

3 回答 3

11

您要么想要字符串 eval,它将字符串评估为 Perl 代码

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

或者更安全的方法可能是使用代码引用

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

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

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

于 2012-08-15T19:50:27.130 回答
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 》一书中有详细介绍

于 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 回答