微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

perl – 嵌套闭包和捕获的变量

我有这个带有嵌套闭包的例子,它演示了内存泄漏

use v5.10;
use strict;

package Awesome;

sub new {
    bless {steps => [],surprise => undef},shift;
}

sub say {
    print "awesome: ",$_[1],"\n";
}

sub prepare {
    my ($self,@steps) = @_;

    for my $s (@steps) {
        push @{$self->{steps}},sub {
            $self->say($s);

            if ($s eq 'pony') {
                $self->{surprise} = sub {
                    $s;
                }
            }
        };
    }
}

sub make {
    my $self = shift;

    while (my $step = shift @{$self->{steps}}) {
        $step->();
    }

    if ($self->{surprise}) {
        printf("And you have surprise: %s\n",$self->{surprise}->());
    }
}

sub DESTROY {
    warn "destroying";
}

package main;

my $a = Awesome->new;
$a->prepare('barbie','pony','flash');
$a->make();

我的perl输出

awesome: barbie
awesome: pony
awesome: flash
And you have surprise: pony
destroying at /tmp/t.pl line 43 during global destruction.

而这个“在全局破坏期间”意味着物体不能以正常方式被破坏,因为它有一些循环引用.

但是,唯一的循环引用是由

push @{$self->{steps}},sub {
            $self->say($s);

我们在第一次关闭时使用$self.然后在make()里面我们将删除这些步骤和循环引用.但看起来这个嵌套的封闭与“惊喜”会产生问题.例如,如果我们不将“pony”传递给prepare(),那么输出将如预期的那样好:

awesome: barbie
awesome: flash
destroying at /tmp/t.pl line 43.

那么,perl中的嵌套闭包是否捕获了与已经捕获的上层闭包相同的变量,即使我们没有使用它们?

解决方法

Perl过去常常在嵌套的闭包中过度捕获,但自5.18以来它不会这样做.

$tail -n 9 a.pl   # Modified to make clearer when the object is destroyed.
package main;

{
   my $a = Awesome->new;
   $a->prepare('barbie','flash');
   $a->make();
}

print "done.\n";

 

$5.16.3t/bin/perl a.pl
awesome: barbie
awesome: pony
awesome: flash
And you have surprise: pony
done.
destroying at a.pl line 43 during global destruction.

 

$5.18.2t/bin/perl a.pl
awesome: barbie
awesome: pony
awesome: flash
And you have surprise: pony
destroying at a.pl line 43.
done.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐