我经常发现能够在离开当前范围时安排执行代码很有用.在我以前的TCL生活中,一位朋友创建了一个名为defer的函数.
它启用了以下代码:
设置fp [open“x”]
推迟(“关闭$fp”);
当前范围退出时调用的.主要的好处是无论我如何/在何处留下范围,它总是被调用.
所以我在Perl中实现了类似的东西,但似乎有一种更简单的方法.评论批评欢迎.
我在Perl中的方式:
>创建一个全局的绑定变量,该变量包含要执行的子数组.
>每当我想安排在退出时调用fn时,我使用local来更改数组.
当我离开当前范围时,Perl将全局更改为先前的值
因为全局是绑定的,我知道这个值发生变化的时候可以调用列表中的subs.
实际代码如下.
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";
解决方法
好吧,如果你使用词法文件句柄(而不是旧式的裸字文件句柄),你的具体案例已经处理好了.对于其他情况,您可以始终使用保证在超出范围时转至零引用的对象的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}(); }
ETA:我更喜欢brian的名字,Scope :: OnExit是一个更具描述性的名字.