2012-06-29 25 views
14

comparación usando los perl -w -Mstrict:¿Qué está pasando cuando my() es condicional?

# case Alpha 
print $c; 

...

# case Bravo 
if (0) { 
    my $c = 1; 
} 

print $c; 

...

# case Charlie 
my $c = 1 if 0; 
print $c; 

Alpha y Bravo tanto se quejan del símbolo global que carezcan de denominación paquete explícito, el cual es de esperar. Pero Charlie no da la misma advertencia, sólo que el valor es inicializado, que huele muy parecido:

# case Delta 
my $c; 
print $c; 

¿Qué está pasando exactamente debajo del capó? (Aunque algo como esto nunca debería escribirse para el código de producción)

+1

En el caso Bravo, '$ c' está en el ámbito léxico a la' Si (0) ... 'bloque, y es una error (bajo 'use strict') para referirse a él fuera de ese bloque. – mob

+5

Por cierto, el comportamiento de 'my $ c = 1 if 0; ... $ c ... 'está oficialmente indefinido (y documentado como tal), lo que significa que no está permitido y puede dar lugar a un comportamiento no deseado (por ejemplo, bloqueo). Bueno, no se bloqueará, pero podría :) – ikegami

+1

@ikegami hmm tienes toda la razón, aparece en la sección "modificadores de estado" de perlsyn. buen recordatorio! –

Respuesta

14

Puede pensar que una declaración my tiene una acción en tiempo de compilación y en tiempo de ejecución. En tiempo de compilación, una declaración my le dice al compilador que tome nota de que existe un símbolo y estará disponible hasta el final del alcance léxico actual. Una asignación u otro uso del símbolo en esa declaración tendrá lugar en tiempo de ejecución.

Así que su ejemplo

my $c = 1 if 0; 

es como

my $c;   # compile-time declaration, initialized to undef 
$c = 1 if 0; # runtime -- as written has no effect 

Tenga en cuenta que esta distinción tiempo de compilación/tiempo de ejecución le permite escribir código como este.

my $DEBUG; # lexical scope variable declared at compile-time 
BEGIN { 
    $DEBUG = $ENV{MY_DEBUG}; # statement executed at compile-time 
}; 

Ahora puede adivinar cuál es el resultado de este programa?

my $c = 3; 
BEGIN { 
    print "\$c is $c\n"; 
    $c = 4; 
} 
print "\$c is $c\n"; 
+0

¡Una respuesta INCREÍBLE! La distinción en tiempo de compilación era la clave que faltaba. ¡Muchas gracias! –

+4

'my' tiene un efecto de tiempo de ejecución como dices, ¡pero no mencionaste de qué se trata! [Coloca una directiva en la pila para borrar la variable en la salida del alcance, luego devuelve la var como un valor l. Bien, es probable que no hayas mencionado eso. :) – ikegami

6

mob's answer es una gran explicación de lo que ocurre actualmente (y por qué), pero no se olvide que perldoc perlsyn nos dice:

NOTA: El comportamiento de un my, state, o our modificado con un modificador de declaración condicional o construcción de bucle (por ejemplo, my $x if ...) es undefined. El valor de la variable my puede ser undef, cualquier valor previamente asignado, o posiblemente cualquier otra cosa. No confíe en ello. Las versiones futuras de perl pueden hacer algo diferente desde la versión de perl que lo pruebe. Aquí hay dragones.

No cuente ese resultado o la explicación que sigue siendo cierto en futuras versiones de Perl. (Aunque es probable que sea.)

2

El "mi $ foo = val si cond " construir y su comportamiento indefinido me ha mordido muchas veces a lo largo de los años.Me gustaría que el compilador simplemente lo rechazara (¿por qué mantener algo en el lenguaje que tiene un comportamiento indefinido ?!), pero presumiblemente esto no se puede hacer por compatibilidad con versiones anteriores u otras razones. La mejor solución que he encontrado es para evitar que con perlcritic:

http://search.cpan.org/perldoc?Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations

+0

Perlcritic nunca es la mejor solución para nada. – tchrist

+3

¿Qué alternativa tengo si quiero evitar que esta construcción tóxica se use accidentalmente? –

Cuestiones relacionadas