perl – DESTROY以意想不到的顺序调用

前端之家收集整理的这篇文章主要介绍了perl – DESTROY以意想不到的顺序调用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我开始注意到 Scope::Guard的奇怪之处.

>如果我将一个$guard变量取消作为sub中的最后一个语句,那么后卫的子变量就会得到
比我预期的要晚.
>如果我不取消它,或者我做了什么
(任何)在undef $guard之后,当引用退出时它会被调用
记录范围.我想知道为什么.

代码也可以在here找到

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
并得到完全相同的结果,至少对我来说意外.

我期待mySub()中的$mySubGuard应该首先销毁
并且应该销毁调用mySub()的范围中的$scopeGuard
持续.所以输出如下:

shouldDestroyFirst
 mySub returned a undefined value
 shouldDestroyLast
 done

如果我在mySub中使用undef $mySubGuard行,我会得到以上输出.
如果我不在mySub中使用undef $mySubGuard行,我会得到以下输出

mySub returned a undefined value
shouldDestroyLast
shouldDestroyFirst
done

所以,看起来mySub()的$mySubGuard被破坏了
在外部范围的本地变量被销毁之后.

为什么行为不同只是因为我取消了即将发生的变量
超出范围?为什么要做的事情至关重要
然后?

解决方法

它看起来像是某种优化.如果你取消变量并且之后不使用它,它会被放入某种队列以检查魔法或其他东西.但是,如果你之后做了什么,那么它就会成为DESTROY.

此外,可能存在一个错误,因为你在说“返回上下文”中没有它,所以有一个正在检查某个变量的变量的副本.也许Perl保留了一个引用,它随后会清理并调用范围的结束.

您还会注意到,在取消防守后,任何其他声明都会导致预期的行为.包括PBP建议结束所有潜艇的返回.达米安的一个显而易见的原因是它避免了意想不到的副作用.

问题解决了:就像取消防守一样容易,你可以直接运行它的处理程序.不要将undef guards作为sub的最后一个(隐式返回)语句.有理由明确地将undef守卫(例如你想要运行他们的处理程序)进行进一步处理.

这是令人困惑和意外的,但绝对不会在完成或标准化的代码中出现.

猜你在找的Perl相关文章