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パフォーマンスと依存関係の問題により受け入れられません。したがって、それは2番目のオプションを除外しているようです.

最初に戻ると、 の新しい値が$_の範囲外に出ないようにする唯一の方法gotoは、変更をローカライズしない (実行可能なオプションではない) か、または のようなものを実装することuplevel_localですgoto_with_local

PadWalkerSub::UplevelScope::Upper、およびその他を含むあらゆる種類の順列を試してみましたが、適切なタイミングでクリーンアップし、ラップしないB::Hooks::EndOfScope堅牢なソリューションを思い付くことができませんでした。$_caller

この場合に機能するパターンを見つけた人はいますか?

(SO の質問:別のスタック フレームで Perl 変数をローカライズするにはどうすればよいですか?は関連していますが、保持すること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 に答える