2015-09-29 9 views
28

Ho appena dato un frammento di codice:Che cos'è "% _" in perl?

@list = grep { !$_{$_}++ } @list; 

quanto un idioma per la deduplicazione. Sembra funzionare, ma - non c'è %_ elencato in perlvar.

avrei normalmente a scrivere quanto sopra dichiarando %seen es .:

my %seen; my @list = grep { not $seen{$_}++ } @list; 

Ma %_ sembra funzionare, anche se sembra essere portata globale. Qualcuno può indicarmi un riferimento per questo? (O almeno rassicurami che fare quanto sopra non sta distruggendo qualcosa di importante!)

+9

Ecco alcune discussioni al riguardo: http://www.perlmonks.org/?node_id=11757 –

+0

Intrigante. Quindi può essere semplice come un residuo del typeglob '_'? Mi chiedo se ci sia qualcosa di più recente di 15 anni fa. (Ma suppongo che se non è cambiato, non ci sarebbe alcuna ragione per questo). – Sobrique

+0

Non che tu abbia bisogno di un 'local% _;' nel primo snippet per lo stesso motivo per cui hai "my% seen;" nel secondo. – ikegami

risposta

23

È un hash. È possibile avere un hash denominato _ perché _ è un nome valido per una variabile. (Sono sicuro che si ha familiarità con $_ e @_.)

No Perl builtin attualmente imposta o legge %_ implicitamente, ma le variabili di punteggiatura come %_ sono riservati.

I nomi di variabili in Perl possono anche essere una sequenza di cifre o un singolo carattere di punteggiatura o controllo (con il carattere di controllo letterale deprecato). Questi nomi sono tutti riservati per usi speciali da Perl


nota che le variabili di punteggiatura sono anche speciali, nel senso che sono "globali super". Ciò significa che il numero non valido %_ fa riferimento a %_ nel pacchetto radice, non %_ nel pacchetto corrente.

$ perl -E' 
    %::x = (name => "%::x" ); 
    %::_ = (name => "%::_" ); 
    %Foo::x = (name => "%Foo::x"); 
    %Foo::_ = (name => "%Foo::_"); 

    package Foo; 

    say "%::x = $::x{name}"; 
    say "%::_ = $::_{name}"; 
    say "%Foo::x = $Foo::x{name}"; 
    say "%Foo::_ = $Foo::_{name}"; 

    say "%x  = $x{name}"; 
    say "%_  = $_{name}"; 
' 
%::x = %::x 
%::_ = %::_ 
%Foo::x = %Foo::x 
%Foo::_ = %Foo::_ 
%x  = %Foo::x 
%_  = %::_  <-- surprise! 

Questo significa che dimenticando di utilizzare local %_ (come avete fatto) può avere effetti molto vasta portata.