2010-02-25 16 views
6

¿Por qué funciona el siguiente fragmento de código? ¿Y qué mal podría ser posible usando esto? Pero en serio, ¿hay alguna razón, el código en ${} se evalúa en absoluto y luego se utiliza como referencia escalar?

use strict; 
no strict 'refs'; 

our $message = "Hello world!"; 
print "${ lc 'MESSAGE' }\n";
+4

Usted declaró explícitamente que quería utilizar referencias simbólicas y 'perl' hizo su oferta. –

+0

Así es como funciona la desreferenciación. Puede encontrar útil: http://perlmonks.org/?node=References+quick+reference – ysth

Respuesta

2

Está bien, unless you use symbolic references. Supongamos el siguiente código:

my %messages = (hello => "Hello world!", bye => "Bye-bye, world!"); 
sub get_message_ref { return \$messages{$_[0]} }; # returns scalarref 
print "${ get_message_ref('bye') }\n"; 

de acuerdo, su utilidad no es obvio con scalarrefs, pero es muy útil con arrayrefs.

print "keys: @{[keys %messages]}\n"; 
+0

http://stackoverflow.com/tags/perl+symbolic-reference –

+0

No me gusta dependiendo de la configuración de '$ "', así que solo usaría eso para una expresión que devuelva un escalar único. Y para eso, '" $ {\ expr} "' es tan bueno como '" @ {[expr]} "', si es menos simétrico. – ysth

+0

@ysth Ok, me has atrapado. Estoy de acuerdo contigo.Pero cuando solo estás escribiendo un guión de una sola vez, está perfectamente bien. – codeholic

4

Desde el "Using References" section of the perlref documentation:

cualquier lugar que había puesto un identificador (o cadena de identificadores) como parte de un nombre de variable o subprograma, se puede reemplazar el identificador con un bloque de devolver una referencia del tipo correcto. En otras palabras, los ejemplos anteriores podrían escribirse así:

$bar = ${$scalarref}; 
push(@{$arrayref}, $filename); 
${$arrayref}[0] = "January"; 
${$hashref}{"KEY"} = "VALUE"; 
&{$coderef}(1,2,3); 
$globref->print("output\n"); # iff IO::Handle is loaded 

Es cierto que es un poco tonto para usar los curlies en este caso, pero el bloque puede contener cualquier expresión arbitraria, en particular, las expresiones subíndice:

&{ $dispatch{$index} }(1,2,3); # call correct routine 

Debido a poder omitir las curlies para el caso simple de $$x, la gente a menudo cometen el error de visualización de los símbolos de eliminación de referencias como los operadores adecuados, y se preguntan acerca de su preferencia. Sin embargo, si lo fueran, podría usar paréntesis en lugar de llaves. Ese no es el caso. Considera la diferencia a continuación; caso 0 es una versión corta a mano de la caja 1, no Caso 2:

$$hashref{"KEY"} = "VALUE";  # CASE 0 
${$hashref}{"KEY"} = "VALUE";  # CASE 1 
${$hashref{"KEY"}} = "VALUE";  # CASE 2 
${$hashref->{"KEY"}} = "VALUE"; # CASE 3 

Caso 2 también es engañoso en el que está accediendo a una variable llamada %hashref, no eliminación de referencias a través $hashref con el hash que es presumiblemente referencia. Ese sería el caso 3.

Más adelante en "referencias simbólicas":

Nos dijeron que las referencias a la existencia de primavera como sea necesario si no están definidos, pero no nos dicen lo que pasa si un valor usado como referencia ya está definido, pero no es una referencia difícil. Si lo usa como referencia, se tratará como una referencia simbólica. Es decir, se considera que el valor del escalar es el nombre de una variable, en lugar de un enlace directo a un valor (posiblemente) anónimo.

+0

Gracias por la extensa explicación sobre los refs, pero la pregunta era por qué el contenido de * {...} se evalúa en una cadena de comillas dobles y si este comportamiento tiene aplicaciones útiles. :) – willert

+1

@willert Sí, y cité pasajes específicos en la documentación que explican lo que está sucediendo: observe el comienzo de la primera frase citada (énfasis agregado): "DONDEQUIERA que ponga un identificador ... puede reemplazar el identificador con un BLOQUE ... "Un bloque Perl es un código arbitrario rodeado de llaves. –

12

Explicamos esto en profundidad en Intermediate Perl.

La sintaxis general para las búsquedas de variables es:

SIGIL BLOCK INDEXY-THING 

Para un simple escalar que se parece a:

print $ { foo }; 

Probablemente han visto este cuando es necesario separar un nombre de variable de las cosas que rodean es:

print "abc${foo}def\n"; 

Si solo tiene un identificador de Perl en el bloque y sin ensuciar alrededor, puede dejar fuera de los apoyos, que es el caso común:

print $foo; 

Sin embargo, esto es lo mismo para la eliminación de referencias referencia:

SIGIL BLOCK-RETURNING-REFERENCE INDEXY-THINGS 

Si la cosa que se ponga en el bloque es una referencia, Perl intenta eliminar la referencia como pediste también:

my $ref = \ '12345'; 
print $  { $ref }; 

Eso es un bloque real, aunque, y no sólo el azúcar. Puede tener tantas declaraciones como quiera ahí:

print $  { my $ref = \ '1234'; $ref }; 

Ahora que no sólo está especificando un identificador de Perl, por lo que Perl no asume que se está dando un identificador y se ejecuta el código y usos el resultado como referencia. Considere la diferencia entre estos say declaraciones casi idénticas:

use 5.010; 
our $foo = "I'm the scalar"; 

sub foo { \ "I'm the sub" } 

say ${foo}; 
say ${foo;}; 

En ese segundo say Perl ve el punto y coma, se da cuenta de que no es un identificador, interpreta el código dentro de las llaves como texto, y devuelve el resultado. Como el resultado es una referencia, usa el ${...} para desreferenciarlo. No importa dónde hagas esto, para que lo hagas dentro de una cadena de comillas dobles no es especial.

También, observe el our allí. Eso es importante ahora que vas a considerar algo un poco más complejo:

use 5.010; 
our $foo = "I'm the scalar"; 

sub foo { \ "I'm the sub" } 
sub baz { 'foo' } 

say ${foo}; 
say ${foo;}; 
say ${baz;}; 

Perl intreprets ese último say como código y ve el resultado no es una referencia; es la cadena simple foo. Perl ve que no es una referencia, pero ahora está en un contexto de desreferenciación, por lo que hace una referencia simbólica (como Greg Bacon describes). Como las referencias simbólicas funcionan con variables en la tabla de símbolos, esa $foo tenía que ser una variable de paquete.

Dado que es fácil estropear esto, strict tiene un práctico control para ello. Sin embargo, cuando lo apagas, no te sorprendas cuando te muerda. :)

Cuestiones relacionadas