[Perl] Fragmento de un closure ...
Salvador Ortiz Garcia
sog@msg.com.mx
Wed, 15 Oct 2003 11:04:59 -0500
On Mon, 2003-10-13 at 22:57, Manuel Rabade wrote:
> On Mon, Oct 13, 2003 at 09:35:09PM -0500, Sergio Rojas wrote:
> > Saludos Perleros!
> >
> > Tengo el siguiente fragmento de un closure:
Nada de fragmento, plantilla es un generador de closures en toda la
forma.
> >
> > 1 sub plantilla{
> > 2 my $x = $_[0];
> > 3 return sub {
> > 4 print "$x $_[0] \n";
> > 5 }
> > 6 }
> >
> >
> > La pregunta es: porque el escalar $x conserva su valor en las lineas
> > 2 y 4, y el elemento del arreglo $_[0] no. Se sobreescribe o algo asi
> > al llamar la subrutina anidada?
> >
>
> Poruque el arreglo @_ contiene los parametros pasados a una subrutina y al
> invocar 'sub' se limpia @_ y se le cargan los valores que le pasas, en este caso
> ninguno.
Salvo que en el código mostrado nadie aún está invocando al closure,
solo creándolo. (La invocación a 'sub', constructor del closue no le
hace nada a @_)
>
> Ademas por el ambito de $x conservara su valor en todo el bloque en el que fue
> declarada (de la linea 1 a 6).
>
> Corrijanme si me equivoco gurus de la lista :-P.
Fundamentalmente tu explicación es correcta. Sólo la formalizaré:
Al llamar a plantilla, con
my $closureA = platilla('foo');
Es claro que en [2] se crea una variable lexicográfica '$x' con el valor
'foo', tomado de los argumentos de la invocación de plantilla.
En [3] plantilla crea un closure, que precisamente por serlo captura el
ambito lexicográfico, y plantilla devuelve una referencia al mismo.
Por lo tanto '$closureA' es una referencia al closure creado, que si
ahora invocamos con:
&{$closureA}('valor'); # o $closureA->('valor'); al gusto del cliente
'valor' se convierte en argumento del closure, en $_[0], y $x conserva
el valor que el closure tiene capturado en su ambito.
De ahí la salida "foo valor".
Si a continuación se ejecutara:
my $clousureB = plantilla('bar');
Se estaría creando un segundo closure, que en el ambito capturado
tendría a 'bar' como valor de '$x', pero el valor de '$_[0]' dependerá
de lo que se le pase como argumento al momento al momento de que se le
invocara:
$closureB->('otro');
Resultando en "bar otro".
De lo anterior queda claro que mientras '$x' en las líneas [2] y [3] es
la misma variable, '$_[0]' en [2] es el argumento con que se invoca a
plantilla, y '$_[0]' en [3] es el argumento con que se invoque al
closure creado.
Y tanto $closureA como $closureB tienen capturada su propia instancia de
'$x'.
Saludos.
--
Salvador Ortiz Garcia <sog@msg.com.mx>
Matías Software Group