假设我有以下代码:
my $compiled = eval 'sub { print( "Hello World\n" ); }';
Run Code Online (Sandbox Code Playgroud)
我可以这样写:
$compiled->();
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在假设我创建了10个函数:
my @fns = ();
for ( my $i = 0; $i < 10; $i++ ) {
push( @fns, eval "sub { print( 'I am function $i\n' ); }" );
}
Run Code Online (Sandbox Code Playgroud)
我可以按如下方式调用这10个函数:
foreach ( @fns ) {
$_->();
}
Run Code Online (Sandbox Code Playgroud)
现在,我想创建一个动态函数,它可以显式调用我的10个函数中的每一个:
my $evalcode = "sub {";
foreach ( @fns ) {
# if I print $_ it shows something like
# "CODE(0x94084f8)", but trying to
# call "CODE(0x94084f8)->()" is invalid
$evalcode .= "$_->();";
}
$evalcode .= "}";
my $dynamic_fn = eval $evalcode;
$dynamic_fn->();
Run Code Online (Sandbox Code Playgroud)
是否可以对子例程进行字符串化引用并直接调用它?
PS为什么,你问?因为我想编写一个动态例程来构造一系列if ( m/.../ ) { } elsif ( m/.../ ) { } ...检查,然后根据输入字符串调用动态函数.
raf*_*afl 14
您可能希望使用常规的词法闭包,而不是字符串evals:
my @functions;
for my $i (0 .. 9) {
push @functions, sub { print "I am function $i\n" };
}
my $call_all_funcs = sub {
for my $func (@functions) {
$func->();
}
};
$call_all_funcs->();
Run Code Online (Sandbox Code Playgroud)
也可以根据其地址检索代码引用,但这样更复杂,更难理解,并且通常不是一个好主意.
如何使用闭包而不是eval字符串?
sub combine_subrefs {
my @subs = @_;
return sub { foreach my $subref (@subs) { $subref->() } };
}
my $dynamic_fn = combine_subrefs( @fns );
$dynamic_fn->();
Run Code Online (Sandbox Code Playgroud)
我相信你可以适应这个来做你提到的elsif事情.
重新:为什么,你问?因为我想编写一个动态例程,构造一个if(m /.../){} elsif(m /.../){} ...链,然后根据输入字符串调用动态函数.
要创建一个像上面描述的if&elsif链,可以不必诉诸eval:
use 5.012;
use warnings;
my $build_ifelse_dispatch_table = sub {
my @functions = @_;
sub {
my $text = shift;
for (@functions) {
my ($re, $code) = @$_;
if ($text =~ $re) {
$code->();
last;
}
}
};
};
my $dispatch_on = $build_ifelse_dispatch_table->(
[ qr/tom/ => sub { say "Tom!" } ], # if (m/tom/) { ... }
[ qr/dick/ => sub { say "Dick!" } ], # elsif (m/dick/) { ... }
[ qr/harry/ => sub { say "Harry!" } ], # elsif (m/harry/) { ... }
);
$dispatch_on->( 'peeping tom' ); # Tom!
$dispatch_on->( 'spotty dick pudding' ); # Dick!
$dispatch_on->( 'harry potter' ); # Harry!
$dispatch_on->( 'Tom, dick and harry' ); # Dick!
Run Code Online (Sandbox Code Playgroud)
参考:维基百科在调度表上的条目.
/ I3az /
| 归档时间: |
|
| 查看次数: |
841 次 |
| 最近记录: |