Desmitificando el globo Perl(*)
(2)
En esta pregunta, el cartel preguntó cómo hacer lo siguiente en una línea:
sub my_sub {
my $ref_array = shift;
my @array = @$ref_array;
}
que con mi conocimiento de la magia básica de Perl evitaría usando simplemente algo como:
sub my_sub {
my $ref_array = shift;
for (@$ref_array) {
#do somthing with $_ here
};
#use $ref_array->[$element] here
}
Sin embargo, en esta respuesta, uno de los monjes locales de SO, Tchrist, sugirió:
sub my_sub {
local *array = shift();
#use @array here
}
Cuando le pregunté
Al tratar de aprender la magia de Perl de nivel medio, ¿puedo preguntar qué es lo que están configurando a qué se refiere aquí? ¿Está configurando una referencia a @array a la matriz de referencia que se ha pasado? ¿Cómo sabes que creas @array y no% array o $ array? ¿Dónde puedo obtener más información sobre este operador * (perlop?). ¡Gracias!
Me sugirieron que lo preguntara como una nueva publicación, aunque él dio buenas referencias. De todos modos, aquí va? ¿Puede alguien explicar qué se asigna a qué y cómo se crea @array en lugar de quizás% array o $ array? Gracias.
Asignación a un glob
*glob = VALUE
contiene algo de magia que depende del tipo de VALUE
(es decir, el valor de retorno de, digamos, Scalar::Util::reftype(VALUE)
). Si VALUE
es una referencia a un escalar, una matriz, un hash o una subrutina, solo se sobrescribirá esa entrada en la tabla de símbolos.
Este idioma
local *array = shift();
#use @array here
funciona como se documenta cuando el primer argumento de la subrutina es una referencia de matriz. Si el primer argumento fuera, por ejemplo, una referencia escalar, entonces solo la $array
afectaría a $array
y no a @array
.
Un pequeño script de demostración para ver lo que está pasando:
no strict;
sub F {
local *array = shift;
print "/@array = @array/n";
print "/$array = $array/n";
print "/%array = ",%array,"/n";
print "------------------/n";
}
$array = "original scalar";
%array = ("original" => "hash");
@array = ("orignal","array");
$foo = "foo";
@foo = ("foo","bar");
%foo = ("FOO" => "foo");
F ["new","array"]; # array reference
F /"new scalar"; # scalar reference
F {"new" => "hash"}; # hash reference
F *foo; # typeglob
F ''foo''; # not a reference, but name of assigned variable
F ''something else''; # not a reference
F (); # undef
Salida:
@array = new array $array = original scalar %array = originalhash ------------------ @array = orignal array $array = new scalar %array = originalhash ------------------ @array = orignal array $array = original scalar %array = newhash ------------------ @array = foo bar $array = foo %array = FOOfoo ------------------ @array = foo bar $array = foo %array = FOOfoo ------------------ @array = $array = %array = ------------------ @array = orignal array $array = original scalar %array = originalhash ------------------
Doc adicional en perlmod
y perldata
. En los días anteriores a que las referencias formaran parte de Perl, este modismo era útil para pasar matrices y hashes a subrutinas.
Con mi conocimiento de Perl, que con toda certeza no soy un mago, aventuraré una respuesta. El operador * asigna la entrada de la tabla de símbolos. Como lo entiendo, @array,% array y $ array se refieren a la misma entrada de la tabla de símbolos para la cadena ''array'', pero a diferentes campos en esa entrada: los campos ARRAY, HASH y SCALAR. Así que asignando local *array = shift;
en realidad asigna la entrada de la tabla de símbolos local completa para ''matriz'' (incluidos los campos ARRAY, HASH y SCALAR) a lo que se pasó en el llamador.