2010-02-25 3 views
6

Pourquoi l'extrait suivant fonctionne-t-il? Et quel mal pourrait-il être possible d'utiliser cela? Mais sérieusement, y at-il une raison, le code dans ${} est évalué du tout et ensuite utilisé comme référence scalaire?

use strict; 
no strict 'refs'; 

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

Vous avez explicitement déclaré que vous vouliez utiliser des références symboliques et 'perl' a fait votre offre. –

+0

Voilà comment fonctionne le déréférencement. Vous pourriez trouver utile: http://perlmonks.org/?node=References+quick+reference – ysth

Répondre

2

C'est bon, unless you use symbolic references. Supposons que le code suivant:

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

D'accord, son utilité est pas évident avec scalarrefs, mais il est très utile avec arrayrefs.

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

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

+0

Je n'aime pas selon le réglage de '$ "', donc je ne l'utiliserais que pour une expression renvoyant un seul scalaire Et pour cela, '" $ {\ expr} "' est aussi bon que '" @ {[expr]} "', moins symétrique. – ysth

+0

@ysth Ok, vous m'avez attrapé, je suis d'accord avec vous.Mais quand vous écrivez juste un script unique, c'est parfaitement ok. – codeholic

4

De l'"Using References" section of the perlref documentation:

Où que vous mettiez un identifiant (ou une chaîne d'identifiants) dans le cadre d'un nom de variable ou sous-programme, vous pouvez remplacer l'identifiant d'un bloc qui retourne une référence du type correct. En d'autres termes, les exemples précédents pourraient être écrits comme ceci:

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

Certes, il est un peu ridicule d'utiliser les Curlies dans ce cas, mais le bloc peut contenir toute expression arbitraire, en particulier, indicés expressions:

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

en raison d'être en mesure d'omettre les Curlies pour le cas simple de $$x, les gens font souvent l'erreur de considérer le déréférencement comme les opérateurs appropriés et se demander au sujet de leur priorité. Si c'était le cas, vous pourriez utiliser des parenthèses à la place des accolades. Ce n'est pas le cas. Considérez la différence ci-dessous; cas 0 est une version courte main de cas 1, pas de cas 2:

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

Cas n ° 2 est aussi trompeur que vous accédez à une variable appelée %hashref, sans déréférencer par $hashref le hachage, il est sans doute le référencement. Ce serait le cas 3.

plus tard dans les « références symboliques »:

Nous avons dit que les références à l'existence printemps si nécessaire si elles ne sont pas définis, mais on n'a pas dit ce qui se passe si une valeur utilisé comme référence est déjà défini, mais n'est pas une référence absolue. Si vous l'utilisez comme référence, cela sera traité comme une référence symbolique. C'est-à-dire que la valeur du scalaire est considérée comme le nom d'une variable, plutôt qu'un lien direct vers une valeur (éventuellement) anonyme.

+0

Merci pour l'explication détaillée sur refs, mais la question était de savoir pourquoi le contenu de * {...} est évalué dans une chaîne entre guillemets et si ce comportement a des applications utiles. :) – willert

+1

@willert Oui, et j'ai cité des passages spécifiques dans la documentation qui expliquent ce qui se passe: notez le début de la première phrase (emphase ajoutée): "N'IMPORTE O you vous mettriez un identifiant ... vous pouvez remplacer l'identifiant par un BLOC ... "Un bloc Perl est un code arbitraire entouré d'accolades. –

12

Nous l'expliquons en détail dans Intermediate Perl.

La syntaxe générale pour les recherches variables est:

SIGIL BLOCK INDEXY-THING 

Pour un scalaire simple qui ressemble à:

print $ { foo }; 

Vous avez probablement vu cela quand vous avez besoin de séparer un nom de variable des choses environnantes il:

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

Si vous avez juste un identifiant Perl dans le bloc et pas de gâchis autour, vous pouvez laisser hors les accolades, ce qui est le cas commun:

print $foo; 

Cependant, cela est la même chose pour déréférencer une référence:

SIGIL BLOCK-RETURNING-REFERENCE INDEXY-THINGS 

Si la chose que vous obtenez en le bloc est une référence, Perl tente de déréférencer comme vous demande aussi:

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

C'est un vrai bloc cependant, et pas seulement le sucre. Vous pouvez avoir autant de déclarations que vous aimez là:

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

Maintenant, vous n'êtes pas seulement spécifier un identifiant Perl, Perl ne suppose pas que vous lui donner un identifiant et il exécute le code et les utilisations le résultat comme référence. Pensez à la différence entre ces say presque identiques déclarations:

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

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

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

Dans ce second say Perl voit le point-virgule, ce n'est pas réalise un identifiant, interprète le code à l'intérieur des accolades sous forme de texte, et renvoie le résultat. Puisque le résultat est une référence, il utilise le ${...} pour le déréférencer. Peu importe où vous faites cela, de sorte que vous le faites dans une chaîne entre guillemets doubles n'est pas spécial.

Notez également le our là. C'est important maintenant que vous allez envisager quelque chose un peu plus compliqué:

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 cette dernière say code et voit le résultat est une référence; c'est la chaîne simple foo. Perl voit que ce n'est pas une référence mais qu'il est maintenant dans un contexte de déréférencement donc il fait une référence symbolique (comme Greg Bacon describes). Comme les références symboliques fonctionnent avec des variables de la table de symboles, cela signifie que $foo devait être une variable de package.

Puisqu'il est facile de tout gâcher, strict a un contrôle pratique pour cela. Cependant, lorsque vous l'éteignez, ne soyez pas surpris quand il vous mord. :)

Questions connexes