6

AUTOLOAD在开发使用或其他子例程调度技术的 Perl 模块时,我曾多次遇到以下模式:

sub AUTOLOAD {
    my $self = $_[0];

    my $code = $self->figure_out_code_ref( $AUTOLOAD );

    goto &$code;
}

这工作正常,并caller看到正确的范围。

现在我想做的是$_$self执行&$code. 这将是这样的:

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  
}

由于性能和依赖性问题,涉及包装的解决方案caller是不可接受的。所以这似乎排除了第二种选择。

回到第一个,在 期间防止新值$_超出范围的唯一方法goto是不本地化更改(不是可行的选项)或实施某种uplevel_localor goto_with_local

我玩过各种涉及PadWalker, Sub::Uplevel,和其他的排列Scope::UpperB::Hooks::EndOfScope但还没有想出一个健壮的解决方案,可以$_在正确的时间清理,并且不换行caller

有没有人找到适用于这种情况的模式?

(SO 问题:How can I localize Perl variables in a different stack frame?是相关的,但保留caller不是必需的,最终答案是使用不同的方法,因此该解决方案在这种情况下没有帮助)

4

2 回答 2

1

Sub::Uplevel 似乎可以工作——至少对于不涉及 AUTOLOAD 的简单情况:

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

当然,这并没有真正本地化父范围中的变量,但我认为即使可以,您也不会真正想要这样做。您只想$_在通话期间进行本地化。

于 2010-07-28T21:46:01.450 回答
1

goto用于指出的 perlfunc 文档(已添加重点)

这种goto-&NAME形式与“goto”的其他形式完全不同。事实上,它根本不是一般意义上的 goto,也没有其他 goto 的污名。相反,它退出当前子例程(丢失由 设置的任何更改local ......</p>

什么样的性能问题允许通过自动加载而不是通过包装器进行间接寻址?

于 2010-07-28T22:03:23.047 回答