En el momento de su creación una subrutina - sea anónima o no - toma los valores de las variables del ámbito en el que se encuentra. El ámbito léxico que engloba a la subrutina en el momento de su creación determina una clausura. Un ejemplo:
lhp@nereida:~/Lperl/src$ cat -n closure2.pl 1 #!/usr/bin/perl -w 2 use strict; 3 my $name = 1000; 4 { 5 my $name = $name--; 6 7 sub pr { 8 $name++; 9 return "closure: $name\n"; 10 } 11 } 12 13 print $name,"\n"; 14 print pr(); 15 print pr(); 16 print pr();cuando se ejecuta produce la siguiente salida:
lhp@nereida:~/Lperl/src$ closure2.pl 999 closure: 1001 closure: 1002 closure: 1003
En condiciones normales Perl liberaría la memoria correspondiente
a la variable name
de la línea 5 al final de su ámbito.
Sin embargo, la
subrutina pr
que la usa continúa visible y
la variable name
se conserva mientras la rutina
este en uso. La única forma de acceder a la variable
name
de la línea 5
es a través de la subrutina pr
.
Esta es una de las característica de una clausura: subrutinas que recuerdan el estado del entorno en el momento de su creación preservando las variables del ámbito léxico que les rodea, incluso después de la desaparición de dicho ámbito léxico.
En el siguiente ejemplo
la subrutina tutu
recibe un número y
retorna una subrutina que multiplica su argumento por dicho
número. El programa principal aplica crea varias subrutinas
y las aplica a una secuencia de números especificados:
lhp@nereida:~/Lperl/src$ closure3.pl 3 1 2 3 4 Multiplicar por 3: (3 6 9 12) Multiplicar por -1: (-1 -2 -3 -4)
La subrutina creada dinámicamente
recuerda el valor de la variable
léxica $n
en el momento de su creación.
El bucle de la línea 19 crea diferentes clausuras
$t
que acceden a diferentes instancias
de la variable léxica $n
.
lhp@nereida:~/Lperl/src$ cat -n closure3.pl 1 #!/usr/bin/perl -w 2 use strict; 3 use Scalar::Util qw(looks_like_number); 4 5 sub tutu { 6 my $n = shift; 7 8 sub { 9 my $x = shift; die "Se esperaba un numero\n" unless looks_like_number($n); 10 return $x*$n; 11 } 12 } 13 14 ########### main ################################# 15 die "Uso:\n$0 num1 num2 num3 ...\n" unless (@ARGV > 1); 16 my $n = shift; die "Se esperaba un numero\n" unless looks_like_number($n); 17 18 19 for my $f ($n, -1) { 20 my $t = tutu($f); 21 my @a = map { $t->($_) } @ARGV; 22 print "Multiplicar por $f: (@a)\n"; 23 }