正如标题所说,在Perl中,如何保存包含子例程引用列表的哈希?例如,我有以下哈希,其中包含对其他库中包含的子例程的引用:
my %testMap = (
helloTest => \&runHello,
goodbyeTest => \&runGoodbye,
);
当我尝试在以下事项中使用Data::Dumper时:
my($out) = new FileHandle ">$fileName";
my $serialized => Data::Dumper->Dump([\%testMap], [$HASH_REFERENCE]);
print $out $serialized;
close $out;
我最终得到的文件如下所示:
$testMap = {
'goodbyeTest' => sub { "DUMMY" },
'helloTest' => sub { "DUMMY" }
};
当我希望输出看起来像原始列表中的内容时,有没有办法做到这一点?
到目前为止,Data :: Dumper和Storable的一些实验没有发现任何内容,我怀疑它是由于实际的代码不能用于正在运行的代码。
答案 0 :(得分:5)
Storable
已能够序列化coderef。
use strict;
use warnings;
use Storable;
use Data::Dump 'dump';
{
no warnings; # Suppress 'used only once' warning
$Storable::Deparse = 1; # Needs to be set to true as per docs
$Storable::Eval = 1; # Same as above
}
sub hello_world { print "Hello world!\n" }
my %hash = (
helloTest => \&hello_world,
byeTest => sub { print "Goodbye!\n" },
);
store \%hash, 'file'; # Could use freeze/thaw for
my $cloned = retrieve( 'file' ); # in-memory serialization
$cloned->{helloTest}(); # Prints 'Hello world!'
答案 1 :(得分:2)
将$Data::Dumper::Deparse
设为真值。
这使用B::Deparse
从操作码重建源代码。这通常但不总是有效。
$ perl -MData::Dumper -e 'sub foo { print "Hello world" };' \
> -e '$Data::Dumper::Deparse=1; print Dumper \&foo'
$VAR1 = sub {
print 'Hello world';
};
如果要解析Perl源代码文件并提取子例程的文本,那就是一个非常不同的问题。但there's a package for that也是如此:
# quick and dirty sub extractor
use PPI;
use Data::Dumper;
$doc = PPI::Document->new( "your_source_code_file_name" );
foreach $sub ( @{$doc->find( 'PPI::Statement::Sub' )} ) {
@t = $sub->tokens;
$name = $t[2];
$code = "sub " . join q//, @t[3..$#t];
$teh_codez{$name} = $code;
}
print Data::Dumper::Dumper \%teh_codez;
答案 2 :(得分:2)
首先,Data :: Dumper是一个调试工具,而不是一个序列化工具。做后者并不是那么好。至少,请务必设置Purity
选项。这将使它在一些不会起作用的情况下起作用。但是,它仍然存在打破别名的问题。
Storable应该用于非平凡的数据,我会使用JSON::XS或YAML模块来处理琐碎的数据。
其次,通过设置Deparse
选项可以尝试。
use Data::Dumper qw( Dumper );
my $serialised;
{
local $Data::Dumper::Purity = 1;
local $Data::Dumper::Deparse = 1;
$serialised = Dumper($struct);
}
对于闭包和XS函数将失败,并且它不会捕获有效的pragma。
my $struct = { f => do { my $x = 123; sub { $x } } };
产生
$VAR1 = {
'f' => sub {
$x;
}
};
答案 3 :(得分:1)
我建议您使用要调用的子例程的 names 存储哈希值,然后在检索后将它们解析为子例程引用
此代码显示了这个想法
use strict;
use warnings;
my %testMap = (
helloTest => 'runHello',
goodbyeTest => 'runGoodbye',
);
$testMap{$_} = \&{$testMap{$_}} for keys %testMap;
$testMap{helloTest}();
$testMap{goodbyeTest}();
sub runHello {
print "runHello\n";
}
sub runGoodbye {
print "runGoodbye\n";
}