如何在Perl中序列化闭包?

6

我认为最好通过一个例子来说明:

use strict;
use warnings;
use 5.010;
use Storable qw(nstore retrieve);

local $Storable::Deparse = 1;
local $Storable::Eval    = 1;

sub sub_generator {
    my ($x) = @_;

    return sub {
        my ($y) = @_;
        return $x + $y;
    };
}

my $sub = sub_generator(1000);
say $sub->(1); # gives 1001
nstore( $sub, "/tmp/sub.store" );
$sub = retrieve("/tmp/sub.store");
say $sub->(1); # gives 1

当我转储 /tmp/sub.store 时,我看到:

$VAR1 = sub {
            package Storable;
            use warnings;
            use strict 'refs';
            my($y) = @_;
            return $x + $y;
        }

但是在这个子程序中,$x从未被定义。我期望由sub_generator生成的子程序在生成时将$x替换为其实际值。我应该怎么解决?

注意,这个问题与这个问题有关。


也许现在是时候退后一步,考虑一下是否序列化子程序是个好主意?在我的职业生涯中,我很少遇到有这种需要的情况。 - Ether
@Ether 我采纳了使用对象的建议。出于某种原因,我一直在 Perl 中避免使用对象,直到你们向我介绍了 Moose,使得一切都变得更加美好。 - David B
1个回答

5

很不幸,我认为Storable不能处理闭包。但是,还有其他CPAN模块可以序列化闭包。例如:Data::Dump::Streamer

use 5.012;
use warnings;
use Data::Dump::Streamer;

sub sub_generator {
    my ($x) = @_;

    return sub {
        my ($y) = @_;
        return $x + $y;
    };
}

my $sub = sub_generator(1000);
say $sub->(1); # gives 1001

my $serialised = Dump( $sub )->Out;
my $copy = do {
    my $CODE1 = undef;
    eval $serialised;
    $CODE1;
};

say $copy->(2); # gives 1002
say $sub->(1);  # still gives 1001

这是打印序列化代码时的样子,代码如下:say Dump $sub;
my ($x);
$x = 1000;
$CODE1 = sub {
           use warnings;
           use strict 'refs';
           BEGIN {
             $^H{'feature_unicode'} = q(1);
             $^H{'feature_say'} = q(1);
             $^H{'feature_state'} = q(1);
             $^H{'feature_switch'} = q(1);
           }
           my($y) = @_;
           return $x + $y;
         };


更新

请参阅Perl5 porters邮件列表中的Storable和Closures线程。它确认了我对Storable和闭包的看法。

/I3az/


我做错了什么?我得到了一个空文件:use Data::Dump::Streamer; my $h={A=>1, B=>2}; open (my $fh, ">", "/tmp/DEL"); Dump($h)->To($fh) or die; close ($fh); - David B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接