Idealmente, l'autore della funzione avrebbe voluto utilizzare
sub fact {
my ($n) = @_;
my $_fact; $_fact = sub {
my ($n, $prod) = @_;
return $prod if $n == 0;
return $_fact->($n-1, $n*$prod);
};
return $_fact->($n, 1);
}
Purtroppo, che ha una perdita di memoria. Il sotto sub ha un riferimento a $_fact
, che contiene un riferimento al sub anonimo. $_fact
dovrebbe essere cancellato per interrompere il riferimento all'uscita.
sub fact {
my ($n) = @_;
my $_fact;
$_fact = sub {
my ($n, $prod) = @_;
return $prod if $n == 0;
return $_fact->($n-1, $n*$prod);
};
my $rv;
my $e = eval { $rv = $_fact->($n, 1); 1 } ? undef : ([email protected] || 'Unknown');
$_fact = undef;
die $e if $e
return $rv;
}
Ma questo è BRUTTO! Un modo per evitare il problema è l'utilizzo di Y combinator. Un modo molto più semplice per evitare il problema è quello di memorizzare il codice di riferimento in una variabile del pacchetto invece di una variabile lessicale (poiché solo le variabili lessicali sono catturate dai sottotitoli). Questo è ciò che fa il codice che hai postato. Tenete a mente che
*_fact = sub { ... };
è fondamentalmente una versione di runtime di
sub _fact { ... }
Sia assegnare il sub a fessura CODICE del simbolo _fact
.
Detto questo, 5.16 ha introdotto una correzione migliore:
use feature qw(current_sub);
sub fact {
my ($n) = @_;
my $_fact = sub {
my ($n, $prod) = @_;
return $prod if $n == 0;
return __SUB__->($n-1, $n*$prod);
};
return $_fact->($n, 1);
}
"Qual è esattamente la funzione/scopo di * davanti _fact" –
@ikegami, che dire di http://codepad.org/80KSqye4? –
Non perde, ma è una soluzione scadente. Rimuove la ricorsione della coda che era ovviamente un fattore guida nel design del sub. '$ n? $ n * fatto ($ n-1): 1' sarebbe stato sufficiente altrimenti. L'eliminazione della ricorsione della coda lo rende inefficiente ovunque. Cambiando il sub esterno per finire con 'my $ rv = $ _fact (...); undef $ _fact; $ rv' sarebbe più appropriato. – ikegami