3
package JustTesting;
use strict;
use warnings;

sub new {
    my $self = {};
    bless($self, shift);
    END { $self->goodbye() };
    return $self;
}

sub goodbye {
    print "Goodbye.\n";
}

package main;
my $this = JustTesting->new();

输出:

变量“$self”不会在 ./test 第 10 行保持共享。
再见。

显然它有效,我可以no warnings在 END 块内抑制警告。但我想知道是否有更好的方法来做到这一点。

我尝试使用这样的匿名子:

my $cleanup = sub { $self->goodbye() };
END { $cleanup->() };

然后像这样:

END { sub { $self->goodbye() }->() };

但我总是得到同样的警告。

4

5 回答 5

22

你很可能想要DESTROY而不是END. 另请参阅perltoot 中的析构函数部分

package JustTesting;
use strict;
use warnings;

sub new {
    my $self = {};
    bless($self, shift);
    return $self;
}

sub goodbye {
    print "Goodbye.\n";
}

sub DESTROY {
    my ($self) = @_;
    $self->goodbye()
};


package main;
{
    say "entering scope";
    my $this = JustTesting->new();
    say "leaving scope";
}
say "left scope";

输出:

进入范围
离开范围
再见。
左范围
于 2009-12-16T14:01:21.663 回答
8

仅供参考,我附上了daxim的正确答案Moose版本。

use 5.012;
use warnings;

{
    package JustTesting;
    use Moose;
    use namespace::clean -except => 'meta';

    sub goodbye { say "Goodbye." }

    sub DEMOLISH {
        my ($self) = @_;
        $self->goodbye;
    }
}

{
    say "entering scope";
    my $this = JustTesting->new();
    say "leaving scope"; 
}

say "left scope";

注意析构函数DEMOLISH子程序的使用。

注意。您会发现 DESTROY 仍然有效,但 DEMOLISH 是正确的 Moosey 方式。

/I3az/

于 2010-06-21T08:11:52.737 回答
4

首先,请参阅my()嵌套子例程中的作用域变量以获得解释。

DESTROY其次,我认为您应该根据您要实现的目标使用或使用辅助类。

于 2009-12-16T14:02:15.417 回答
3

警告的原因是因为即使它看起来不像,perlEND块等同于声明常规(命名)子,并且在另一个子内声明的命名子的行为不是什么您想要 -在第一次调用时将绑定到块$self内部,并且它将在程序的剩余生命周期中继续看到相同的值 - 创建的第一个实例。第一个实例将拥有该块持有的引用,并且在程序结束之前不会被销毁,并且任何后续实例根本不会调用该块。END$selfsub newnewENDEND

与命名 subs 不同,匿名 subs 没有这个问题,因为每次遇到它们的定义时都会重新构造它们,因此它们关闭的任何变量都尽可能晚地绑定,并且您实际想要的值被捕获。

当其他人已经告诉您您想要的是DESTROY相反的东西时,这是一个很长的解释,但我认为您可能想知道您编写的代码实际发生了什么。

于 2009-12-17T00:49:45.467 回答
1

END块被调用时,$cleanup 已经被释放了。要对变量进行任何操作,您应该改用析构函数。

请参阅perldoc perlobj中的“析构函数” 。

于 2009-12-16T18:16:23.910 回答