2014-01-09 88 views
7

這是我不明白的東西。爲什麼Perl函數「map」給出錯誤「Map not enough arguments」

該腳本正常工作(注意在地圖載體作用的串聯):

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my %aa = map { 'a' . '' => 1 } (1..3); 

print Dumper \%aa; 

__END__ 
output: 

$VAR1 = { 
      'a' => 1 
     }; 

但無連接地圖不起作用。這裏是我期望工作的腳本,但它不是:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my %aa = map { 'a' => 1 } (1..3); 

print Dumper \%aa; 
__END__ 
output: 

Not enough arguments for map at e.pl line 7, near "} (" 
syntax error at e.pl line 7, near "} (" 
Global symbol "%aa" requires explicit package name at e.pl line 9. 
Execution of e.pl aborted due to compilation errors. 

你能解釋這種行爲嗎?

回答

12

Perl使用啓發式方法來決定是否你使用的第一個例子:

map { STATEMENTS } LIST; # or 
map EXPR, LIST; 

因爲雖然「{」通常是塊的開始,但它也可能是hashref的開始。

這些啓發式算法在令牌流(IIRC兩個令牌)中看起來並不遙遠。

可以強制 「{」 應被解釋爲使用塊:

map {; STATEMENTS } LIST; # the semicolon acts as a disambigator 

可以強制 「{」 應被解釋爲使用散列:

map +{ LIST }, LIST; # the plus sign acts as a disambigator 

grep遭受類似。 (技術上,do也是如此,因爲可以給出一個hashref作爲參數,然後它會被串化並視爲它是一個文件名。雖然這很奇怪。)

6

Documentationmap

由於Perl不向前看的是,關閉}它採取處它在處理基於它只是{後發現一個猜測。通常它得到它的權利,但如果它不就不會意識到什麼是錯的,直到它到達}

給出的例子:

%hash = map { "\L$_" => 1 } @array # perl guesses EXPR. wrong 
%hash = map { +"\L$_" => 1 } @array # perl guesses BLOCK. right 

因此增加+會給你同你給

my %aa = map { +'a'=> 1 } (1..3); 
+1

沒什麼用你的答案來做,但是基於編程語言的猜測語法並不能使我成爲好設計。 – antred

2

大括號在上下文中有點模棱兩可的地圖。他們可以圍繞一個塊,因爲你打算,或者他們可以是一個匿名哈希構造函數。 perl分析器中有一些模糊邏輯,它試圖猜測你的意思。

你的第二種情況看起來更像是一個匿名哈希perl。

請參閱perldoc for map這解釋了這一點並提供了一些解決方法。

3

Perl的manpage entry for 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 it's dealing with based on 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 comma at end 

to get a list of anonymous hashes each with only one entry 
apiece. 

在此基礎上,擺脫串聯雜牌的,你需要你的語法調整至以下內容之一:

my %aa = map { +'a' => 1 } (1..3); 
my %aa = map { ('a' => 1) } (1..3); 
my %aa = map +('a' => 1), (1..3);