2010-02-25 14 views
6

Dlaczego poniższy fragment w ogóle działa? A jakie zło może być możliwe przy użyciu tego? Ale poważnie, czy istnieje jakikolwiek powód, kod w ${} jest w ogóle oceniany, a następnie używany jako odniesienie skalarne?

use strict; 
no strict 'refs'; 

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

Wyraźnie stwierdziliście, że chcecie użyć referencji symbolicznych, a "perl" złożyło Waszą ofertę. –

+0

W ten sposób działa dereferencja. Pomocne może okazać się: http://perlmonks.org/?node=References+quick+reference – ysth

Odpowiedz

2

Jest ok, unless you use symbolic references. Załóżmy, że następujący kod:

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

Zgadzam się, jego przydatność nie jest oczywiste z scalarrefs, ale jest bardzo przydatny przy arrayrefs.

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

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

+0

Nie podoba mi się w zależności od ustawienia '$ "', więc użyłbym tego tylko dla wyrażenia zwracającego pojedynczy skalar, a do tego '' $ {\ expr} "' jest tak samo dobre jak '" @ {[wyrażenie}} "", jeśli mniej symetryczne. – ysth

+0

@ysth Ok, złapałeś mnie, zgadzam się z tobą.Ale kiedy piszesz jednorazowy scenariusz, wszystko jest w porządku. – codeholic

4

Od "Using References" section of the perlref documentation:

Gdziekolwiek chcesz umieścić identyfikator (lub łańcuch identyfikatorów) jako część nazwy zmiennej lub podprogramu, można zastąpić identyfikator bloku powrocie odniesienie prawidłowego typu. Innymi słowy, poprzednie przykłady można zapisać tak:

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

Trzeba przyznać, że to trochę głupie użycie nawiasów klamrowych w tym przypadku, ale blok może zawierać dowolną wyrażenie, w szczególności indeksowaną wyrażeń:

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

Ponieważ jest w stanie pominąć nawiasów klamrowych dla prostego przypadku $$x, ludzie często popełniają błąd postrzegania symboli dereferencji jako prawdziwych operatorów i zastanawiam się o ich pierwszeństwa. Gdyby tak było, zamiast nawiasów klamrowych można użyć nawiasów. Nie o to chodzi. Rozważ różnicę poniżej; przypadek 0 jest wersja short-hand z przypadku 1, nie Przypadek 2:

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

Przypadek 2 jest również zwodniczy, że masz dostęp do zmiennej o nazwie %hashref nie dereferencing przez $hashref do mieszania to przypuszczalnie odwołującego. To byłby przypadek 3.

Później w „symbolicznych odniesień”:

Powiedzieliśmy, że odniesienia wiosny do istnienia jako konieczne, jeśli są niezdefiniowane, ale nie mówią, co się stanie, jeśli wartość używany jako odniesienie jest już zdefiniowany, ale nie jest twardym odniesieniem. Jeśli użyjesz go jako odniesienia, będzie traktowane jako odniesienie symboliczne. Oznacza to, że wartość skalarna jest nazwą zmiennej, a nie bezpośrednim linkiem do (prawdopodobnie) anonimowej wartości.

+0

Dziękuję za obszerne wyjaśnienie dotyczące ref, ale chodziło o to, dlaczego zawartość * {...} zostanie oceniona w podwójnym cudzysłowu i czy to zachowanie ma jakieś użyteczne aplikacje. :) – willert

+1

@willert Tak, i zacytowałem konkretne fragmenty w dokumentacji, które wyjaśniają, co się dzieje: zwróć uwagę na początek pierwszego cytowanego zdania (podkreślenie dodane): "GDZIEKOLWIEK wstawiłeś identyfikator ... możesz zastąpić identyfikator BLOKIEM ... "Blok Perla jest arbitralnym kodem otoczonym nawiasami klamrowymi. –

12

Wyjaśnimy to szczegółowo pod numerem Intermediate Perl.

Ogólna składnia dla zmiennych wyszukiwań jest:

SIGIL BLOCK INDEXY-THING 

Dla prostego skalara, który wygląda tak:

print $ { foo }; 

Widzieliście pewnie to kiedy trzeba oddzielić nazwę zmiennej z rzeczy otaczających to:

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

Jeśli masz tylko identyfikator Perla w bloku i no otaczający bałagan, można pozostawić wyłączony szelki, który jest częsty przypadek:

print $foo; 

Jednak jest to samo dla dereferencji odniesienie:

SIGIL BLOCK-RETURNING-REFERENCE INDEXY-THINGS 

Jeśli sprawa, że ​​pojawi się w blok jest odniesieniem, Perl próbuje dereference nim jak poprosiłeś go zbyt:

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

to prawdziwy blok choć i to nie tylko cukier. Można mieć wiele sprawozdań, jak chcesz się tam:

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

Teraz jesteś nie tylko podając identyfikator Perl, więc Perl nie zakładamy, że dajesz mu identyfikator i wykonuje kod i wykorzystuje wynik jako odniesienie. Rozważmy różnicę między tymi niemal identycznych say oświadczenia:

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

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

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

w tym drugim say Perl widzi średnik, zdaje sobie sprawę, że nie jest to identyfikator, interpretuje kod wewnątrz szelki jak tekst i zwraca wynik. Ponieważ wynikiem jest odwołanie, używa on ${...} do dereferencji. Nie ma znaczenia, gdzie to robisz, więc robisz to w ciągu cudzysłowu nie jest wyjątkowy.

Zwróć też uwagę na our. To ważne, że teraz masz zamiar rozważyć coś nieco bardziej skomplikowane:

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 tej ostatniej say jako kod i widzi wynik nie jest punktem odniesienia; to prosty ciąg foo. Perl widzi, że nie jest to odniesienie, ale teraz znajduje się w kontekście dereferencyjnym, więc robi symboliczne odniesienie (jako Greg Bacon describes). Ponieważ odniesienia symboliczne działają ze zmiennymi w tabeli symboli, ta $foo musi być zmienną pakietową.

Ponieważ łatwo to zepsuć, strict ma przydatny czek na to. Jednak kiedy go wyłączysz, nie zdziw się, kiedy Cię ugryzie. :)

Powiązane problemy