Historicamente, Perl supporta l'ambito lessicale delle variabili, il che consente di utilizzare le chiusure (closures) — funzioni che salvano l'ambiente esterno. Il problema sorge quando una chiusura fa riferimento a variabili al di fuori del proprio ambito o quando strutture annidate creano riferimenti circolari, portando a perdite di memoria a causa di una gestione poco accurata dei riferimenti.
La soluzione è utilizzare le chiusure per creare fabbriche di funzioni e uno stile funzionale, e allo stesso tempo ricordare la gestione corretta dei riferimenti quando si chiudono le variabili dall'ambito esterno.
Esempio di codice:
sub make_counter { my $count = 0; return sub { $count++; }; } my $counter = make_counter(); print $counter->(), " "; # 0 print $counter->(), " "; # 1
Caratteristiche chiave:
Cosa succede se restituisco una funzione anonima che fa riferimento a se stessa?
Verrà creata un'associazione circolare che Perl non potrà raccogliere automaticamente con il raccoglitore di rifiuti. Questo porterà a una perdita di memoria. Per risolvere, utilizzare riferimenti deboli, modulo Scalar::Util:
use Scalar::Util qw(weaken); my $foo; $foo = sub { ... $foo ... }; weaken($foo);
La chiusura cattura sempre una "copia" della variabile, o è un riferimento alla stessa variabile?
La chiusura opera sempre sulla variabile attuale, il suo ambito viene fissato al momento della creazione della chiusura. Pertanto, la variabile è la stessa per tutte le chiamate della funzione chiusura.
È possibile fare in modo che la chiusura lavori con uno stato modificabile al di fuori di essa, ma non mantenga un riferimento forte?
Sì, utilizzare riferimenti deboli (Scalar::Util::weaken) o strutturare il codice in modo che i riferimenti siano mantenuti solo dove necessario (ad esempio, passare dati dall'esterno ad ogni chiamata della chiusura).
Creato un callback-closure che chiude $self da un oggetto OO, e rimane all'interno di un hash di callback. Dopo la distruzione dell'oggetto, la memoria non viene liberata.
Vantaggi:
Svantaggi:
La chiusura fa correttamente riferimento debole a $self usando Scalar::Util::weaken:
use Scalar::Util qw(weaken); my $cb = sub { my $self = shift; weaken($self); ... };
Vantaggi:
Svantaggi: