我可以在 Perl 中的硬编码地址处调用子例程吗?
假设我有以下代码:
my $compiled = eval 'sub { print( "Hello World\n" ); }';
我可以通过编写来调用它:
$compiled->();
到目前为止一切顺利。现在想象我创建 10 个函数:
my @fns = ();
for ( my $i = 0; $i < 10; $i++ ) {
push( @fns, eval "sub { print( 'I am function $i\n' ); }" );
}
我可以按如下方式调用这 10 个函数:
foreach ( @fns ) {
$_->();
}
现在,我想创建一个动态函数,显式调用我的 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->();
是否可以采用对子例程的字符串化引用并直接调用它?
PS你问为什么?因为我想编写一个动态例程,构造一个 if ( m/.../ ) { } elsif ( m/.../ ) { } ...
检查链,然后调用取决于输入字符串的动态函数。
Let's say I have the following piece of code:
my $compiled = eval 'sub { print( "Hello World\n" ); }';
I can call this by writing:
$compiled->();
So far so good. Now imagine I create 10 functions:
my @fns = ();
for ( my $i = 0; $i < 10; $i++ ) {
push( @fns, eval "sub { print( 'I am function $i\n' ); }" );
}
I can call these 10 functions as follows:
foreach ( @fns ) {
$_->();
}
Now, I want to create a dynamic function that calls each of my 10 functions explicitly:
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->();
Is it possible to take a stringified reference to a subroutine and call this directly?
PS why, you ask? Because I would like to write a dynamic routine that constructs a chain of if ( m/.../ ) { } elsif ( m/.../ ) { } ...
checks that then call dynamic functions depending on the input string.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可能希望使用常规的词法闭包而不是字符串评估:
也可以根据其地址检索代码引用,但这会更复杂,更难以理解,并且通常不是一个好主意。
Instead of string evals, you might want to use regular lexical closures:
It is also possible to retrieve a code reference based in its address, but that'd be much more elaborate, harder to understand, and generally not a very good idea.
使用闭包而不是 eval 字符串怎么样?
我相信你也可以调整它来完成你提到的 elsif 事情。
How about using a closure instead of an eval string?
I'm sure you can adapt this to do the elsif thing you mentioned as well.
回复:你问为什么?因为我想编写一个动态例程,构造一个 if ( m/.../ ) { } elsif ( m/.../ ) { } ... 检查链,然后根据输入字符串调用动态函数.
创建一个if &像上面描述的 elsif 链可以完成,而不必求助于
eval< /code>
:
参考:调度表上的维基百科条目。
/I3az/
re: why, you ask? Because I would like to write a dynamic routine that constructs a chain of if ( m/.../ ) { } elsif ( m/.../ ) { } ... checks that then call dynamic functions depending on the input string.
To create an if & elsif chain like you described above can be done without having to resort to
eval
:ref: Wikipedia entry on Dispatch Table.
/I3az/
当您打印子例程引用时,您会看到类似
CODE(0xDEADBEEF)
的内容,因为这就是 Perl 对引用进行字符串化的方式。如果您打印任何类型的不重载字符串化的引用,您会看到这样的事情:通常您不能真正将该值用于任何用途,并且您看到的数字不一定对应于真实的内存地址。
对于您正在做的事情,请参阅我在掌握 Perl 中的动态子例程章节。我谈了很多关于编写子例程和使用匿名子例程可以做的不同事情。像 Data::Constraint 这样的模块甚至可能会给你一些想法。我还在 Perl 如何强制其调用者返回? 的回答中讨论了这一点。
You're seeing something like
CODE(0xDEADBEEF)
when you print a subroutine reference because that's how Perl stringifies references. You see the say sort of thing if you print any sort of reference that doesn't overload stringification:Normally you can't really use that value for anything, and the number you see doesn't correspond necessarily to a real memory address.
For what you're doing, see the dynamic subroutine chapters I have in Mastering Perl. I talk quite a bit about the different things you can do to compose subroutines and work with anonymous subroutines. A module such as Data::Constraint might even give you some ideas. I also talk about this in my answer to How can a Perl force its caller to return?.
也许有可能(请参阅这个类似的问题和解决方案),但也许还有另一种方法。将字符串化代码引用映射到实际代码引用的(全局?)哈希怎么样?
It might be possible (see this similar problem and solutions), but maybe there is another way. How about a (global?) hash that maps stringified code references to the actual code references?