Historycznie, Perl wspierał leksykalny zasięg zmiennych, co pozwala na użycie zamknięć (closures) — funkcji zachowujących zewnętrzne środowisko. Problem pojawia się, gdy zamknięcie odnosi się do zmiennych spoza swojego zasięgu lub gdy zagnieżdżone struktury tworzą cykliczne odniesienia, co prowadzi do wycieków pamięci z powodu nieostrożnego zarządzania odniesieniami.
Rozwiązanie — używać zamknięć do tworzenia fabryk funkcji i stylu funkcyjnego, a jednocześnie pamiętać o poprawnym zarządzaniu odniesieniami przy zamykaniu zmiennych z zewnętrznego zasięgu.
Przykład kodu:
sub make_counter { my $count = 0; return sub { $count++; }; } my $counter = make_counter(); print $counter->(), "\n"; # 0 print $counter->(), "\n"; # 1
Kluczowe cechy:
Co się stanie, jeśli zwrócimy funkcję anonimową, która odnosi się do samej siebie?
Zostanie utworzone cykliczne odniesienie, którego Perl nie będzie w stanie automatycznie zebrać zbieraczem śmieci. Doprowadzi to do wycieku pamięci. Aby to rozwiązać, użyj słabych odniesień, moduł Scalar::Util:
use Scalar::Util qw(weaken); my $foo; $foo = sub { ... $foo ... }; weaken($foo);
Czy zamknięcie zawsze „zatrzymuje” „kopię” zmiennej, czy jest to odniesienie do tej samej zmiennej?
Zamknięcie zawsze operuje na bieżącej zmiennej, jej zasięg jest ustalany przy tworzeniu zamknięcia. W ten sposób zmienna jest jedna i ta sama dla wszystkich wywołań funkcji zamknięcia.
Czy można zrobić tak, aby zamknięcie działało ze zmiennym stanem na zewnątrz, ale nie miało do niego twardego odniesienia?
Tak, użyj słabych odniesień (Scalar::Util::weaken) lub zorganizuj kod, aby odniesienia były przechowywane tylko tam, gdzie to konieczne (na przykład, przekazuj dane z zewnątrz przy każdym wywołaniu zamknięcia).
Utworzono callback-closure, które zamyka $self z obiektu OO i trzyma się w hashu callbacks. Po zniszczeniu obiektu pamięć nie jest zwalniana.
Zalety:
Wady:
Zamknięcie poprawnie słabo odnosi się do $self za pomocą Scalar::Util::weaken:
use Scalar::Util qw(weaken); my $cb = sub { my $self = shift; weaken($self); ... };
Zalety:
Wady: