2011-01-12 8 views
17

Một trong những điều đầu tiên tôi cố gắng học bằng ngôn ngữ lập trình không quen thuộc là cách nó xử lý các bao đóng. Ngữ nghĩa của chúng thường gắn bó với cách ngôn ngữ xử lý các phạm vi và các bit phức tạp khác để hiểu chúng cho thấy một số khía cạnh khác của ngôn ngữ. Plus, đóng cửa là một cấu trúc thực sự mạnh mẽ và thường xuyên cắt giảm số lượng boilerplate tôi phải gõ. Vì vậy, tôi đã rối tung xung quanh với đóng cửa perl và tôi stumbled khi một Gotcha nhỏ:

my @closures; 
foreach (1..3) { 
    # create some closures 
    push @closures, sub { say "I will remember $_"; }; 
} 
foreach (@closures) { 
    # call the closures to see what they remember 
    # the result is not obvious 
    &{$_}(); 
} 

Khi tôi viết đoạn mã trên tôi đã mong đợi để xem

I will remember 1 
I will remember 2 
I will remember 3 

nhưng thay vào đó tôi đã I will remember CODE(0x986c1f0).

Thử nghiệm trên cho thấy rằng $_ phụ thuộc rất bối cảnh và nếu nó xuất hiện trong một đóng cửa thì giá trị của nó không được cố định tại thời điểm tạo kết thúc. Nó hoạt động giống như một tham chiếu. Những gì gotchas khác tôi nên biết khi tạo bao đóng trong perl?

Trả lời

25

Đóng cửa chỉ đóng trên các biến từ vựng; $_ thường là biến toàn cục. Trong 5.10 trở lên, bạn có thể nói my $_; để có từ vựng trong một phạm vi nhất định (mặc dù trong 5.18 điều này đã được khai báo trước đó là thử nghiệm và có thể thay đổi, vì vậy tốt hơn nên sử dụng một số tên biến khác).

này sẽ cho kết quả như bạn mong đợi:

use strict; 
use warnings; 
use 5.010; 
my @closures; 
foreach my $_ (1..3) { 
    # create some closures 
    push @closures, sub { say "I will remember $_"; }; 
} 
foreach (@closures) { 
    # call the closures to see what they remember 
    # the result is not obvious 
    &{$_}(); 
} 
+2

Nhưng điều này khá giống với việc sử dụng 'foreach $ num ...' của tôi. – davidk01

+1

Vì vậy, nếu chúng chỉ đóng các biến từ vựng, điều gì xảy ra với các loại biến khác? Việc đóng cửa có sử dụng giá trị có sẵn trong trang web cuộc gọi như nó không cho '$ _'? – davidk01

+1

@ davidk01: giống như bất kỳ ngôn ngữ lập trình nào khác cho phép các biến toàn cục, các bao đóng thực sự đóng trên biến đó như bình thường. Bạn chỉ cần quên rằng nó toàn cục và do đó có thể thay đổi khi mã khác đặt giá trị của nó thành một cái gì đó khác (giống như bởi chính tiểu trình ẩn danh khi nó được gọi). – slebetman

3

$ _ là một biến toàn cầu và không nên được sử dụng trong đóng cửa. Trước khi sử dụng nó gán cho một biến lexically scoped như được hiển thị bewlow. Điều này sẽ tạo ra dự kiến ​​o/p.

#!/usr/bin/perl -w 

use strict; 
my @closures; 


foreach (1..3) { 
    my $var = $_; 
    push @closures, sub { print "I will remember $var"; }; 
} 

foreach (@closures) { 
    $_->(); 
    print "\n"; 
}