您要做的是将 '$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 》一书中有详细介绍