使用 map 函数的语法错误

Syntax error using map function

我在使用 map 函数的 Perl 程序中遇到了一个奇怪的语法错误。我有一个简单的解决方法(添加看似不必要的括号),所以这不是关键,但我不知道为什么 Perl 在原始代码上报告语法错误,或者为什么添加括号修复它。

我想创建一个散列,将一系列短字符串映射到值 1(基本上是一组数据结构),每个字符串都以“-”开头。我的第一次尝试与此类似:

my %hash = map { "-$_"  => 1 } qw(foo bar);

我认为应该等同于:

my %hash = ( "-foo" => 1, "-bar" => 1 );

Perl 报告语法错误。如果我将 "-$_" 替换为任何单引号或双引号字符串文字,我会收到语法错误。如果我将 "-$_" 替换为 ("-$_"),语法错误就会消失,并且代码可以正常工作。

我在 Perl 5.10.1、5.16.2 和 5.20.0 上得到了相似的结果。

这是一个显示问题的独立脚本(我删除了 - 前缀,因为它似乎不相关):

#!/usr/bin/perl

use strict;
use warnings;

my %h0 = map {   $_   => 1 } qw(foo bar);  # ok
my %h1 = map { ("$_") => 1 } qw(foo bar);  # ok
my %h2 = map {  "$_"  => 1 } qw(foo bar);  # line 8, syntax error
my %h3 = map { 'FOO'  => 1 } qw(foo bar);  # line 9, syntax error
my %h4 = map { "FOO"  => 1 } qw(foo bar);  # line 10, syntax error

以及当我尝试使用 Perl 5.20.0 运行 时的输出:

syntax error at map-bug line 8, near "} qw(foo bar)"
syntax error at map-bug line 9, near "} qw(foo bar)"
syntax error at map-bug line 10, near "} qw(foo bar)"
Execution of map-bug aborted due to compilation errors.

(对于 Perl 5.10.1 和 5.16.2,它还会在第 8 行抱怨 "Not enough arguments for map"。)

我已经确认,当其他两行被注释掉时,三个语法错误中的每一个仍然单独出现,因此第 9 行和第 10 行不是第 8 行的级联错误。

这是 Perl 中的错误,还是我遗漏了 Perl 语法的一些微妙之处,或者其他什么?

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 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 + or semicolon 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 { ("\L$_" => 1) } @array # as does this
    %hash = map {  lc($_) => 1  } @array # and 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.