2013-03-07 6 views
11

Durante la navigazione il codice sorgente ho visto le seguenti righe:Perché questo blocco di mappe contiene un + apparentemente inutile?

my @files_to_keep = qw (file1 file2); 
my %keep = map { + $_ => 1 } @files_to_keep; 

Cosa significa il + fare in questo frammento di codice? Ho usato Data::Dumper per vedere se togliere il segno più non fa nulla, ma i risultati erano gli stessi:

$ perl cleanme.pl 
$VAR1 = { 
      'file1' => 1, 
      'file2' => 1 
     }; 
+0

controllo alla fine dei documenti anche per qualche informazione in più: http://perldoc.perl.org/functions/map.html – squiguy

risposta

12

Questo è utilizzato per prevenire un problema di analisi. Il simbolo più forza l'interprete a comportarsi come un normale blocco e non un'espressione.

Il timore è che forse si sta tentando di creare un riferimento all'hash utilizzando l'altra formulazione (espressione) di map in questo modo.

@array_of_hashrefs = map { "\L$_" => 1 }, @array 

Si noti la virgola. Quindi se il parser indovina che stai facendo questo dato l'istruzione nell'OP, ci sarà un errore di sintassi per la mancanza della virgola! Per vedere la differenza prova a quotare "$_". Per qualsiasi motivo, il parser prende questo quanto basta per innescare il comportamento dell'espressione.

Sì, è una stranezza. Pertanto molti programmatori Perl paranoici extra lanciano il segno più in più del necessario (me incluso).

Ecco gli esempi della documentazione map.

%hash = map { "\L$_" => 1 } @array # perl guesses EXPR. wrong 
%hash = map { +"\L$_" => 1 } @array # perl guesses BLOCK. right 
%hash = map { ("\L$_" => 1) } @array # this also works 
%hash = map { lc($_) => 1 } @array # as does this. 
%hash = map +(lc($_) => 1), @array # this is EXPR and works! 
%hash = map (lc($_), 1), @array # evaluates to (1, @array) 

Per una lettura divertente (stilisticamente) e un caso in cui il parser sbaglia leggere questo: http://blogs.perl.org/users/tom_wyant/2012/01/the-case-of-the-overloaded-curlys.html

+0

NB: Provato altri operatori, ma ottengono anteposto al ' key'. Solo '+' funziona di conseguenza. –

+0

Grazie. Ottengo la sintassi della mappa BLOCK LIST come 'my @squares = map {$ _ * $ _} @numbers;', ma quando usi mai la mappa EXPR LIST? (o forse in un altro modo: sono ancora confuso tra il termine BLOCK ed EXPR) – Alby

+0

Ricorda che un blocco è come una mini subroutine che può fare tutto ciò che Perl potrebbe fare in un sottotitolo. La forma di espressione è più per piccole trasformazioni che non hanno realmente bisogno di un intero blocco, qualcosa come 'my @out = map" hi $ _ ", @inputs;'. Alcune persone preferiscono probabilmente questa forma più semplice, ma io uso sempre il modulo di blocco da solo. –

7

Il unario-plus operatore restituisce semplicemente il suo operando invariato. Aggiungerne uno non cambia nemmeno il contesto.

Nell'esempio che hai fornito, è completamente inutile. Ma ci sono situazioni in cui è utile rendere il prossimo token qualcosa che è innegabilmente un operatore.


Ad esempio, map ha due sintassi.

map EXPR, LIST 

e

map BLOCK LIST 

Un blocco inizia con {, ma così può un'espressione. Ad esempio, { } può essere un blocco o un costruttore di hash.

Quindi, come può map indicare la differenza? Suppone. Il che significa che a volte è sbagliato.

Un'occasione in cui è congetture sbagliato è teh seguente:

map { $_ => 1 }, @list 

Puoi prod in a indovinare correttamente utilizzando + o ;.

map {; ...  # BLOCK 
map +{ ...  # EXPR 

Quindi, in questo caso, è possibile utilizzare

map +{ foo => $_ }, @list 

Ma io preferisco:

map({ foo => $_ }, @list) 

Un altro esempio è quando si omettono le parentesi intorno argomenti, e la prima l'espressione argomento inizia con un paren.

print ($x+$y)*2; # Same as: 2 * print($x+$y) 

Può essere fissato con

print +($x+$y)*2; 

Ma perché mucchio su un hack solo per evitare parentesi? Io preferisco

print(($x+$y)*2); 
Problemi correlati