2008-11-07 12 views
10

Dies schlägt fehl:Warum kompiliert diese map-Anweisung in Perl nicht?

my @a = ("a", "b", "c", "d", "e"); 
my %h = map { "prefix-$_" => 1 } @a; 

mit diesem Fehler:

Not enough arguments for map at foo.pl line 4, near "} @a" 

aber dies funktioniert:

my @a = ("a", "b", "c", "d", "e"); 
my %h = map { "prefix-" . $_ => 1 } @a; 

warum?

Antwort

21

Weil Perl ein EXPR (ein Hash-Verweis zum Beispiel) statt eines BLOCKs erraten. Dies sollte (beachten Sie die '+' Symbol) arbeiten:

my @a = ("a", "b", "c", "d", "e"); 
my %h = map { +"prefix-$_" => 1 } @a; 

Siehe http://perldoc.perl.org/functions/map.html.

11

Von perldoc -f map:

  "{" starts both hash references and blocks, so "map { ..." 
      could be either the start of map BLOCK LIST or map EXPR, LIST. 
      Because perl doesn’t look ahead for the closing "}" it has to 
      take a guess at which its dealing with based what it finds just 
      after the "{". Usually it gets it right, but if it doesn’t it 
      won’t realize something is wrong until it gets to the "}" and 
      encounters the missing (or unexpected) comma. The syntax error 
      will be reported close to the "}" but you’ll need to change 
      something near the "{" such as using a unary "+" to give perl 
      some help: 

      %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) 

      or to force an anon hash constructor use "+{" 

      @hashes = map +{ lc($_), 1 }, @array # EXPR, so needs , at end 

      and you get list of anonymous hashes each with only 1 entry. 
13

Ich ziehe es zu schreiben, dass als

my %h = map { ("prefix-$_" => 1) } @a; 

die Absicht zu zeigen, dass ich eine 2-Element-Liste zurückzukehre.

6

Auch die andere Art und Weise zu tun, was Sie tun, Initialisieren des Hash, können Sie wie folgt tun:

my @a = qw(a b c d e); 
my %h; 
@h{@a} =(); 

Das undef Einträge für jede der fünf Tasten schaffen. Wenn Sie ihnen alle wahren Werte geben wollen, dann tun Sie dies.

@h{@a} = (1) x @a; 

Sie können es auch explizit mit einer Schleife tun;

@h{$_} = 1 for @a; 
1

Ich denke, dass

map { ; "prefix-$_" => 1 } @a; 

mehr idiomatische ist, soweit die Angabe, dass es ein Block von Anweisungen und nicht ein Hash-ref. Sie starten es einfach mit einer Null-Anweisung.

Verwandte Themen