2012-07-11 41 views
8

Tôi bắt đầu nhận thấy điều gì đó kỳ lạ về số Scope::Guard.DESTROY được gọi theo trình tự không mong muốn

  • Nếu tôi undef một biến $guard như báo cáo kết quả cuối cùng trong một tiểu, tiểu của bảo vệ được gọi muộn hơn tôi mong đợi.
  • Nếu tôi không hoàn tác, hoặc nếu tôi làm điều gì đó (mọi thứ) sau undef $guard, nó sẽ được gọi khi tài liệu tham khảo nằm ngoài phạm vi như được ghi lại. Tôi tự hỏi tại sao.

Mã này cũng được tìm thấy 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"; 

Trong đoạn code tôi đã thực hiện Scope::Guard (SGuard trên) chỉ để làm ví dụ của riêng tôi kém của con người như đơn giản càng tốt. Bạn cũng có thể sử dụng Scope::Guard và nhận được kết quả chính xác giống như bất ngờ tối thiểu với tôi.

tôi hy vọng rằng $mySubGuard bên mySub() nên bị hủy diệt đầu tiên và $scopeGuard trong phạm vi mà các cuộc gọi mySub() nên bị phá hủy ngoái. Và do đó, có được sản lượng như:

shouldDestroyFirst 
mySub returned a undefined value 
shouldDestroyLast 
done 

Tôi nhận được sản lượng trên nếu tôi sử dụng undef $mySubGuard dòng trong mySub. Nếu tôi không sử dụng undef $mySubGuard dòng trong mySub, tôi nhận được bên dưới đầu ra:

mySub returned a undefined value 
shouldDestroyLast 
shouldDestroyFirst 
done 

Vì vậy, nó trông giống như $mySubGuard từ mySub() bị phá hủy sau biến địa phương để các phạm vi bên ngoài bị phá hủy.

Tại sao hành vi khác nhau chỉ vì tôi hoàn tác biến số sắp sửa rời khỏi ngoài phạm vi? Và tại sao nó quan trọng cho dù một cái gì đó được thực hiện sau đó?

Trả lời

1

Dường như đó là một số loại tối ưu hóa. Nếu bạn undef một biến và không sử dụng nó sau đó, nó được đặt trong một số loại hàng đợi để kiểm tra ma thuật hoặc một cái gì đó. Nhưng nếu bạn làm bất cứ điều gì sau đó, nó sẽ làm ngay sau đó.

Ngoài ra, có thể có lỗi do bạn đang undef -nhắn nó trong nói "ngữ cảnh trả về", có một bản sao của biến đang được kiểm tra cho một cái gì đó. Và có lẽ Perl giữ lại một tài liệu tham khảo mà sau này nó dọn dẹp và kết thúc phạm vi gọi.

Bạn cũng sẽ nhận thấy rằng bất kỳ tuyên bố nào khác khác sau undef -kết quả cảnh báo về hành vi mong đợi. Bao gồm PBP-khuyến nghị kết thúc tất cả các đăng ký với return. Một trong những lý do rõ ràng của Damian là nó tránh được những tác dụng phụ bất ngờ.

Sự cố đã được giải quyết: dễ dàng như undef -người bảo vệ, bạn có thể chạy trình xử lý của nó thẳng. Không undef bảo vệ như là cuối cùng (ngầm trở lại) tuyên bố của một phụ. Có lý do để hoàn toàn không bảo vệ, chẳng hạn như bạn muốn chạy trình xử lý của họ ngay sau đó, để làm xử lý tiếp theo.

Thật khó hiểu và bất ngờ, nhưng chắc chắn không phải thứ gì đó sẽ phát sinh trong mã hoàn chỉnh hoặc chuẩn hóa.

Các vấn đề liên quan