2010-02-10 12 views
15

En Perl, ¿usar "my" dentro de un ciclo foreach tiene algún efecto? Parece que la variable de índice siempre es local ya sea que se use o no 'my'. Entonces, ¿puedes dejar caer el "mi" dentro del ciclo foreach y aún tener alcance privado dentro del cuerpo del ciclo?¿Cuál es el alcance predeterminado del bucle foreach en Perl?

Como se puede observar, a través del 'para' bucle que hay una diferencia entre el uso/no uso de 'mi':

use strict; 
use warnings; 

my ($x, $y) = ('INIT', 'INIT'); 

my $temp = 0; 

for ($x = 1; $x < 10; $x++) { 
$temp = $x+1; 
} 

print "This is x: $x\n"; # prints 'This is x: 10'. 

for (my $y = 1; $y < 10; $y++) { 
$temp = $y+1; 
} 

print "This is y: $y\n"; # prints 'This is y: INIT'. 

Pero en foreach no parecen tener un efecto:

my ($i, $j) = ('INIT', 'INIT'); 

foreach $i (1..10){ 
    $temp = $i+1; 
} 

print "\nThis is i: $i\n"; # prints 'This is i: INIT'. 



foreach my $j (1..10){ 
    $temp = $j+1; 
} 

print "\nThis is j: $j\n"; # prints 'This is j: INIT'. 
+0

buena observación. – Zacky112

+7

Cubrimos esto en _Learning Perl_, y es el primer párrafo de la documentación para los bucles foreach. :) –

+0

Sugerencia: ¿Qué sucede con su código cuando lo antepone con 'use strict; usa advertencias; '? – Ether

Respuesta

1

Uno de los descubrimientos más dolorosos sobre Perl que realicé fue que la variable "mi" en un bucle foreach no es una copia local. Me encontré frustrado al descubrir que mi matriz estaba siendo destruida.

La única manera alrededor parece ser:


foreach (@array) { 
    my $element = $_; # make a local copy 
    ... 
} 

Si nos fijamos en perldoc se afirma: "la variable de índice bucle foreach es un alias implícito para cada elemento de la lista que está en bucle sobre" y "Si cualquier elemento de LIST es un lvalue, puede modificarlo modificando VAR dentro del ciclo".

+5

+1 interesante y útil, -1 no es relevante para esta pregunta – mob

+0

Tienes razón. Dejando la respuesta de todos modos ya que fue todo un descubrimiento para mí. –

+3

Apesta si no lo espera. Pero también puede ser muy útil. Por ejemplo, si necesita aplicar una transformación a todos los miembros de una matriz: 's/^ \ s + // para @foo;' Lo mismo se aplica a los argumentos secundarios, más 'map' y' grep'. Por cierto, 'List :: MoreUtils' tiene' apply' que es como 'map' pero funciona con una copia local, por lo que puedes hacer' my @bar = apply {s/Q/q/g} @foo; 'sin modificar '@ foo'. – daotoad

13

De http://perldoc.perl.org/perlsyn.html#Foreach-Loops:

El foreach itera bucle sobre un valor de la lista normal y establece la variable VAR ser cada elemento de la lista, a su vez. Si la variable está precedida por la palabra clave my, tiene un alcance léxico y, por lo tanto, es visible solo dentro del ciclo. De lo contrario, la variable es implícitamente local para el ciclo y recupera su valor anterior al salir del ciclo. Si la variable fue declarada previamente con my, usa esa variable en lugar de la global, pero aún está localizada en el ciclo. Esta localización implícita ocurre solo en un ciclo foreach.

+1

del cartel original. Solo quería agregar una síntesis para ayudar a otras personas nuevas en Perl como yo. Si algo está mal, házmelo saber y lo limpiaré. Los términos 'localización/localización implícita' anteriores no son solo términos cualitativos: de hecho, 'local' aquí es una construcción técnica exacta de lenguaje Perl. 'foreach' usa el alcance 'local' dinámico en oposición al alcance 'mi' léxico o el alcance 'paquete' global. Un buen enlace que me ayudó con estos 3 ámbitos http://perl.plover.com/FAQs/Namespaces.html. Antes, estaba confundido, aunque 'local' en los documentos de Perl era lo mismo que 'mi' léxico. –

0

Acabo de hacer algunas investigaciones adicionales sobre este tema tan interesante.

foreach no importa si haces "my $ y;" antes del ciclo tampoco. El iterador todavía sólo cambiar dentro del ámbito:

my $y; 
foreach $y (1..10) {} 

el $ y va a cambiar dentro del ámbito foreach, pero cuando sale, vuelve de nuevo a lo que era antes del bucle.

Pensé que tal vez foreach hace automáticamente "mi $ y;" antes de que se pone en marcha, por lo que trató de modo estricto, pero esa explicación no es suficiente porque entonces todavía exige:

foreach my $y (1..10) {}

en contraposición a:

foreach $y (1..10) {}

... lo que uno podría pensar no eran necesarios si "foreach $ y" era funcionalmente lo mismo que "foreach my $ y".

+0

no son equivalentes, sin embargo. 'foreach my $ y (1..10) {}; imprimir $ y; ' vs ' my $ y; foreach $ y (1..10); imprimir $ y; #mejor comportamiento con 'my' explícito en el bucle foreach' –

11

Hans enlazado a la documentación que describe cómo se ve la variable en el lazo foreach.La distinción es sutil pero podría ser importante:

sub f { return $i } 
$i = 4; 
$m = $n = 0; 

foreach $i (1 .. 10) { $m += f() } 
foreach my $i (1 .. 10) { $n += f() } 

print "Result with localization: $m\n"; # ==> 55 
print "Result with lexical scoping: $n\n"; # ==> 40 
+1

Tu publicación me confundió muchísimo. Esperaba que '$ m' fuera 55, y' $ n' fuera 40. Estaba confundido hasta que ejecuté el script. Creo que tienes un error en los comentarios. – daotoad

+0

Lo siento @daotoad, error en los comentarios. – mob

0

la iteración de un bucle foreach es efectivamente local al bucle. Dicho esto, mantiene directamente el valor de la lista en lo que efectivamente es una llamada por referencia en lugar de por valor. Por lo tanto, si opera en el valor mientras está en el bucle, cambiará el valor en la lista. Sin embargo, la variable de iteración sólo se define en referencia al bucle:

@names = qw(Kirk Spock Bones); 

$officer = "Riker"; 
print "@names $officer\n"; # will print Kirk Spock Bones Riker 

foreach $officer (@names) { 
    $officer .= "y"; 
} 

print "@names $officer\n"; # will print Kirky Spocky Bonesy Riker 

Así, el iterador, en este caso oficial de $, es precedida efectivamente por un 'mi' en cuanto a la retención de cualquier valor que tenía antes de la foreach loop Sin embargo, si los valores que contiene cambian, el cambio volverá a la lista sobre la que está iterando.

Cuestiones relacionadas