câu trả lời
Eric Strom là đúng, và có lẽ những gì bạn muốn xem, nhưng không đi vào chi tiết của sự ràng buộc.
Một lưu ý ngắn gọn về tuổi thọ từ vựng: lexicals được tạo ra tại thời gian biên dịch và thực sự sẵn sàng ngay cả trước khi phạm vi của họ được nhập vào, như ví dụ này cho thấy:
my $i;
BEGIN { $i = 42 }
print $i;
Sau đó, khi họ đi ra khỏi phạm vi, họ sẽ không khả dụng cho đến lần tiếp theo họ nằm trong phạm vi:
print i();
{
my $i;
BEGIN { $i = 42 }
# in the scope of `my $i`, but doesn't actually
# refer to $i, so not a closure over it:
sub i { eval '$i' }
}
print i();
Trong mã của bạn, đóng cửa bị ràng buộc với từ ngữ ban đầu $i
lúc biên dịch. Tuy nhiên, vòng lặp foreach hơi lạ; trong khi my $i
thực sự tạo ra một từ vựng, vòng lặp foreach không sử dụng nó; thay vào đó, nó bí danh nó thành một trong các giá trị lặp trên mỗi lần lặp và sau đó khôi phục nó về trạng thái ban đầu của nó sau vòng lặp. Đóng cửa của bạn như vậy là điều duy nhất tham khảo từ vựng ban đầu $i
.
Một biến thể nhẹ cho thấy phức tạp hơn:
foreach (@foo) {
my $i = $_;
sub printer {
my $blah = shift @_;
print "$blah-$i\n";
}
printer("test");
}
Ở đây, bản gốc $i
được tạo ra tại thời gian biên dịch và đóng cửa liên kết với đó; vòng lặp đầu tiên của vòng lặp đặt nó, nhưng vòng lặp thứ hai của vòng lặp tạo ra một $i
mới không liên kết với việc đóng.
rất thú vị, cảm ơn bạn – Snark