为什么Perl功能" map"给出错误"没有足够的地图参数"

时间:2014-01-09 22:39:43

标签: perl dictionary

这是我不明白的事情。

此脚本正常工作(注意地图功能中的连接):

#!/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.

你能解释一下这种行为吗?

4 个答案:

答案 0 :(得分: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可以作为参数给出,然后将其进行字符串化并将其视为文件名。但这只是奇怪的。)

答案 1 :(得分:6)

根据map的{​​{3}}:

  

因为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);

答案 2 :(得分: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.

基于此,要摆脱连接kludge,您需要将语法调整为其中之一:

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

答案 3 :(得分:2)

在地图的背景下,大括号有点模棱两可。它们可以像你想要的那样围绕一个块,或者它们可以是一个匿名的哈希构造函数。 perl解析器中有一些模糊逻辑,它试图猜测你的意思。

你的第二个案例看起来更像是perl的匿名哈希。

请参阅解释此问题的perldoc for map并提供一些解决方法。