我经常发现能够在离开当前范围时安排执行代码很有用.在我以前的TCL生活中,一位朋友创建了一个名为defer的函数.
它启用了代码:set fp [open"x"] defer("close $ fp");
当前范围退出时调用的.主要的好处是无论我如何/在何处留下范围,它总是被调用.
所以我在Perl中实现了类似的东西,但似乎有一种更简单的方法.评论批评欢迎.
我在Perl中的方式:
实际代码如下.
有一个更好的方法吗?似乎这将是一项常用的功能.
use strict;
package tiescalar;
sub TIESCALAR {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
sub FETCH {
my $self = shift;
return $self->{VAL};
}
sub STORE {
my $self = shift;
my $value = shift;
if (defined($self->{VAL}) && defined($value)) {
foreach my $s (@{$self->{VAL}}) { &$s; }
}
$self->{VAL} = $value;
}
1;
package main;
our $h;
tie($h, 'tiescalar');
$h = [];
printf "1\n";
printf "2\n";
sub main {
printf "3\n";
local $h = [sub{printf "9\n"}];
push(@$h, sub {printf "10\n";});
printf "4\n";
{
local $h = [sub {printf "8\n"; }];
mysub();
printf "7\n";
return;
}
}
sub mysub {
local $h = [sub {printf "6\n"; }];
print "5\n";
}
main();
printf "11\n";
Run Code Online (Sandbox Code Playgroud)
好吧,如果您使用词法文件句柄(而不是旧式的裸字文件句柄),您的特定情况已经得到处理。对于其他情况,您始终可以使用对象的 DESTROY 方法,保证在超出范围时转到零引用:
#!/usr/bin/perl
use strict;
use warnings;
for my $i (1 .. 5) {
my $defer = Defer::Sub->new(sub { print "end\n" });
print "start\n$i\n";
}
package Defer::Sub;
use Carp;
sub new {
my $class = shift;
croak "$class requires a function to call\n" unless @_;
my $self = {
func => shift,
};
return bless $self, $class;
}
sub DESTROY {
my $self = shift;
$self->{func}();
}
Run Code Online (Sandbox Code Playgroud)
ETA:我更喜欢 brian 的名字,Scope::OnExit 是一个更具描述性的名字。