2012-06-06 23 views
13

Si se produce una coincidencia de expresión regular dentro de una evaluación, los cambios en las variables relacionadas con la captura ($ 1, etc.) no son visibles en el entorno externo. ¿Es esto un error?

perlop y perlre no parecen mencionar ninguna de estas restricciones.

Por ejemplo:

use strict; use warnings; 
$_ = "hello"; 
eval '/(.*)/'; 
print "GOT: $1\n"; 

da:

Use of uninitialized value $1 in concatenation (.) or string at -e line 1. 
GOT: 

Una demostración más sucinta es:

perl -we '$_="foo"; eval q(/(.*)/;) ; print "GOT:$1\n";' 

Respuesta

2

Las variables léxicas declaradas dentro de un eval se perderán después de los extremos de eval .

+1

Solía ​​pensar en '$ 1' (y' $ & ', para el caso) como variables * globales *, no * lexicales *. – Lumi

+0

@Lumi son globales pero se declaran implícitamente solo por el primer uso (ver un ejemplo en mi respuesta) – Matteo

+1

@Matteo - No, la noción de * declarar * variables globales (realmente * variables de paquete *) en Perl es engañosa. No es necesario declararlos, ni los integrados ni ningún usuario podrían agregarlos. Solo son valores almacenados en un espacio de nombres.La * necesidad de declaración o calificación completa * solo surge con el 'estricto' pragma: 'mi'-declaración,' nuestra'-declaración (adjunta al paquete pero con alcance léxico), o calificación completa de variables globales no incorporadas. – Lumi

10

prueba de documentación que local las variables zados son el problema aquí está en perlvar of 5.14.0:

Estas variables son de sólo lectura-y dinámicamente con ámbito, a menos que se observa lo contrario.

La naturaleza dinámica de las variables de expresión regular significa que su valor está limitado al bloque que se encuentran en [...]

Tenga en cuenta que este pedazo de documentación es absent from the 5.12.4 perldoc.


El problema es local ized variables. Mi copia de perldoc -f eval (5.12.4) tiene esto que decir:

The assignment to [email protected] occurs before restoration of localised 
variables, which means a temporary is required if you want to 
mask some but not all errors: [...] 

La página de manual no hace una declaración explícita de todas estas variables globales especiales (como $1, $&, y probablemente otros), pero la localización de bloques y la posterior restauración es lo parece suceder aquí.

Las variables se asignan dentro del eval y los valores originales se restauran una vez que queda el bloque eval.

use strict; use warnings; 
use Test::More; 
use constant V => 'hello'; 

$_ = V; 

note '*** block eval'; 
eval { 
     is $_, V, 'input ok'; 
     /(.*)/; 
     is $&, V, 'in eval'; is $1, V, 'in eval'; 
}; 
is $&, V, 'after eval'; is $1, V, 'after eval'; 

note '*** without eval'; 
is $_, V, 'input ok'; 
/(.*)/; 
is $&, V; is $1, V; 

done_testing; 
+0

@Matteo - Como se indicó anteriormente en otro comentario en esta página, '$ 1' no está" implícitamente declarado ". Consulte la actualización en la parte superior de mi respuesta para obtener una referencia de doc que explica este problema. – Lumi

3

La pregunta real ya está respondida, así que aquí está la respuesta de cómo lograr la tarea.

Simplemente use los valores de retorno de eval, que a su vez usa los valores de retorno del operador de coincidencia. $1 es una mierda, evitar.

use strict; use warnings; 
$_ = "hello"; 
my @r = eval '/(.*)/'; 
# (
#  "hello" 
#) 
Cuestiones relacionadas