8

私は何か奇妙なことに気づき始めましたScope::Guard

  • サブの最後のステートメントとして変数の定義を解除する$guardと、ガードのサブが予想よりも遅く呼び出されます。
  • 定義を解除しない場合、または後で何か(何か)を実行しundef $guardた場合、ドキュメントに記載されているように、参照がスコープ外になると呼び出されます。なんでだろうか。

コードもここにあります

my $sClass = 'SGuard';
# Uncomment to use Scope::Guard instead:
# use Scope::Guard; $sClass = 'Scope::Guard';

package SGuard;
sub new {
    my ($class, $sub) = @_;
    return bless { sub => $sub }, $class;
}

sub DESTROY {
    my ($self) = @_;
    $self->{sub}->();
}

package main;
sub mySub {
    my $mySubGuard = $sClass->new(sub { 
         print "shouldDestroyFirst\n" 
    });

    # Do something - any no-op will do.
    undef;

    # Comment out this line and it works
    undef $mySubGuard;

    # Or uncomment the next undef line and it works. Any statement(s) or
    # no-ops will do but we test the return value of mySub to make sure it
    # doesn't return a reference, so undef...

    # undef;
}
{
    my $scopeGuard = $sClass->new(sub { 
        print "shouldDestroyLast\n" 
    });

    # Check that mySub returns undef to ensure the reference *did* go out
    # of scope
    printf "mySub returned a %sdefined value\n", defined mySub() ? "" : "un";
}
print "done\n";

コードでは、例をできるだけ単純にするために、自分の貧乏人Scope::Guard(上記)を作成しました。 また、少なくとも私には予想外のまったく同じ結果をSGuard使用して取得することもできます。Scope::Guard

$mySubGuard内部mySub()を最初に破棄$scopeGuardし、呼び出し元のスコープ内をmySub()最後に破棄することを期待しています。そして、次のような出力を取得します。

 shouldDestroyFirst
 mySub returned a undefined value
 shouldDestroyLast
 done

undef $mySubGuardmySubでlineを使用すると、上記の出力が得られます。undef $mySubGuardmySubで行を使用しない場合、以下の出力が得られます。

mySub returned a undefined value
shouldDestroyLast
shouldDestroyFirst
done

$mySubGuardしたがって、外部スコープにローカルな変数が破棄された後、 frommySub()が破棄されたように見えます。

とにかくスコープから外れそうな変数の定義を解除したからといって、動作が異なるのはなぜですか?そして、なぜ後で何かが行われるかどうかが重要なのでしょうか?

4

1 に答える 1

1

ある種の最適化のようです。変数を後で使用しない場合はundef、マジックなどをチェックするために何らかのキューに入れられます。しかし、後で何かを行うと、その時点で DESTROY が実行されます。

undefまた、 「コンテキストを返す」などでそれを -ing しているため、何かを調べている変数のコピーがあるというバグがある可能性があります。そしておそらく、Perl は後でクリーンアップする参照と呼び出しスコープの終わりを保持します。

また、ガードを -ing した後の他のステートメントは、期待どおりの動作になることにも気付くでしょう。undefPBP が推奨する、すべてのサブスクをreturn. ダミアンの明確な理由の 1 つは、予期しない副作用を回避できることでした。

問題は解決しました: ガードを -ing するのと同じくらい簡単に、undefそのハンドラを直接実行できます。サブルーチンの最後の (暗黙の return) ステートメントとしてガードを undef しないでください。ハンドラーをすぐに実行したいなど、ガードを明示的に undef する理由があり、さらに処理を行います。

これは紛らわしく予想外ですが、完成したコードや標準化されたコードで発生するはずのないものであることは間違いありません。

于 2012-07-11T13:20:53.877 に答える