如何在Perl中将变量本地化到更高的作用域中?
在开发使用如何在Perl中将变量本地化到更高的作用域中?,perl,local,goto,uplevel,Perl,Local,Goto,Uplevel,在开发使用自动加载或其他子例程分派技术的Perl模块时,我曾多次遇到以下模式: sub AUTOLOAD { my $self = $_[0]; my $code = $self->figure_out_code_ref( $AUTOLOAD ); goto &$code; } 这工作正常,caller可以看到正确的范围 现在我想做的是在执行和$code的过程中,将$\ucode>本地设置为等于$self。可能是这样的: sub AUTOLOAD {
自动加载
或其他子例程分派技术的Perl模块时,我曾多次遇到以下模式:
sub AUTOLOAD {
my $self = $_[0];
my $code = $self->figure_out_code_ref( $AUTOLOAD );
goto &$code;
}
这工作正常,caller
可以看到正确的范围
现在我想做的是在执行和$code
的过程中,将$\ucode>本地设置为等于$self
。可能是这样的:
sub AUTOLOAD {
my $self = $_[0];
my $code = $self->figure_out_code_ref( $AUTOLOAD );
local *_ = \$self;
# and now the question is how to call &$code
# goto &$code; # wont work since local scope changes will
# be unrolled before the goto
# &$code; # will preserve the local, but caller will report an
# additional stack frame
}
由于性能和依赖性问题,涉及包装调用方的解决方案是不可接受的。所以这似乎排除了第二种选择
回到第一个问题,防止$\ucode>的新值在goto
期间超出范围的唯一方法是不本地化更改(不是可行的选项),或者实现某种uplevel\u local
或goto\u with\u local
我已经尝试过各种各样的排列,包括PadWalker
、Sub::Uplevel
、Scope::Upper
、B::Hooks::EndOfScope
和其他,但还没能找到一个在正确的时间清理$\ucode>并且不包装调用方的健壮解决方案
有没有人找到一种在这种情况下有效的模式
(所谓的问题:是相关的,但保留调用方并不是一个要求,最终的答案是使用不同的方法,因此解决方案在这种情况下没有帮助)Sub::Uplevel似乎起作用——至少对于不涉及自动加载的简单情况:
use strict;
use warnings;
use Sub::Uplevel;
$_ = 1;
bar();
sub foo {
printf "%s %s %d - %s\n", caller, $_
}
sub bar {
my $code = \&foo;
my $x = 2;
local *_ = \$x;
uplevel 1, $code;
}
输出为:
main c:\temp\foo.pl 6 - 2
当然,这并没有真正地在父范围内本地化变量,但我认为即使可以,您也不会真的希望这样做。您只想在通话期间本地化$。转到的perlfunc文档指出(重点已添加)
goto-&NAME
形式与其他形式的“goto”有很大不同。事实上,它根本不是一个正常意义上的后继,也没有与其他后继相关的污名。相反,它退出当前子例程(丢失本地设置的任何更改)
什么样的性能问题允许通过自动加载而不是通过包装进行间接寻址?老实说,我在这里有点迷茫。但是你能帮我们做一下吗?因此,您可以在本地访问$uu,但也可以访问$套餐:$\说真的,尽管这超出了我的大脑scope@xenoterracide=>我不确定您的软件包范围想法将走向何方,但是$\ucode>(以及大多数其他标点符号变量)在所有软件包中都很常见,并且不能用我们的
来确定软件包范围。词法$\u
(my$\u;
)是一个完全不同的野兽,但这超出了这个问题的范围,请原谅,我不确定我要带它去哪里。但是perl并没有对我们的$大喊大叫代码>所以我假设$也会受到影响;也许假设错了。如果我有一个真实的答案,我会这样回答。这是为了什么?首先,您为什么要本地化$\uuu
,这会带来什么好处?@Ether=>在我的例子中,纯粹是出于风格原因(消除锅炉板代码),这就是为什么我要重视CORE::GLOBAL修改对性能的影响,因为风格上的调整不应该导致深远的性能问题。但我可以想象uplevel\u local
或goto\u with\u local
构造的其他用途。Sub::uplevel
将完成欺骗调用者的任务,但我对它的方式并不着迷(包装和本地化CORE::GLOBAL::caller
)。有关更多详细信息,请参见Sub::Uplevel
的BUGS/Cautions部分。啊,我(错误地)将您的问题理解为“Sub::Uplevel不起作用”,而不是您因为它的工作方式而取消了它的资格。我对性能的关注更多的是针对我没有编写的代码(模块用户)。我不能说他们是否会使用调用者
或广泛使用调用者
的代码,从C内置到userland sub的性能影响可能很大。由于最终的目标只是为您设置$\uucode>的语法精确性,因此很难证明对核心::全局
命名空间的更改是合理的,这可能会导致性能下降。我想我的最终问题是,我不同意在转到
之前展开局部变量的设计决策,因为它似乎不必要地降低了goto-&NAME
构造的能力。我更希望goto-&NAME
从呼叫站点采用本地pad,然后在&NAME
执行结束时回滚本地pad。这可能也比每次弹出和推送作用域堆栈要快。