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行保持共享。
再见。
显然它可以工作,我可以在END块内用no
warnings
来抑制警告。但我想知道是否有更好的方法
怎么做。
我尝试使用这样的匿名子:
my $cleanup = sub { $self->goodbye() };
END { $cleanup->() };
然后像这样:
END { sub { $self->goodbye() }->() };
但我总是得到同样的警告。
答案 0 :(得分:21)
您最有可能想要DESTROY
而不是END
。另请参阅the section on destructors in 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";
输出:
entering scope leaving scope Goodbye. left scope
答案 1 :(得分:7)
仅为了参考未来的读者,我附上了Moose
daxim版本answer的正确destructor。
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";
请注意{{3}}的DEMOLISH
子例程的使用。
NB。你会发现DESTROY仍然有效,但DEMOLISH是正确的Moosey方式。
/ I3az /
答案 2 :(得分:4)
首先,请参阅my()
Scoped Variable in Nested Subroutines以获取解释。
其次,我认为您应该使用DESTROY
或帮助程序类,具体取决于您要实现的目标。
答案 3 :(得分:3)
警告的原因是因为即使它看起来不像它,perl END
块等同于常规(命名)子的声明,以及声明的命名子行为在另一个子内部不是你想要的 - $self
块内的END
将被绑定到$self
第一个时间内sub new
调用new
,它将继续在程序的剩余生命周期中看到相同的值 - 创建的第一个实例。第一个实例将具有END
块所持有的引用,并且在程序结束之前不会被销毁,并且任何后续实例都不会在它们上面调用END
块。
与命名的subs不同,匿名subs没有这个问题,因为它们在每次遇到它们的定义时都会重新构造,因此它们关闭的任何变量都会被尽可能晚地绑定,并且实际需要的值被捕获
这是一个很长的解释,当其他人已经告诉你,你想要的是DESTROY
,但我想你可能想知道你写的代码发生了什么实际
答案 4 :(得分:1)
当调用END
块时,$ cleanup已经被释放。要对变量进行任何操作,您应该使用析构函数。
请参阅perldoc perltoot处的“破坏者”。