Perl 语法细节 - 列出带或不带参数的上下文



这有效:

my $r = someSubroutine( map { ( 0 => $_ ) } @hosts)

这不起作用,给出语法错误:

my $r = someSubroutine( map { 0 => $_ } @hosts)

我想我理解的是,映射后的{ }相当于闭包或匿名子例程。

但是如果我在正常子例程的末尾放一个"value, value",它将返回这些值的列表。如果我在地图中使用这种简洁性,那就是语法错误。

首先,这是一个非常奇怪的说法。map生成的列表如下所示

0, $hosts[0], 0, $hosts[1], 0, $hosts[2], ...

所以分配给哈希是没有用的,因为它与

my  %hash = (0 => $hosts[-1])

map将接受 BLOCK(这是您正在使用的)或其第一个参数的简单表达式。这里的问题是{ 0 => $_ }看起来非常像一个带有单个元素的匿名哈希,这是一个表达式,这就是解析器猜测的。表达式要求在它后面,在第二个参数之前有一个逗号,但是当perl到达map { 0 => $_ } @hosts中的右大括号时,它找不到一个逗号,所以它必须抛出一个语法错误,因为它太远了,无法回溯到左大括号并假设一个块

文档是这样说

{同时启动哈希引用和块,因此map { ...可以是映射块列表或映射 EXPR,列表的开头。因为 Perl 不会展望收盘}所以它必须根据它在{后发现的内容来猜测它正在处理什么。通常它做对了,但如果它没有,它不会意识到有什么问题,直到它到达}并遇到丢失(或意外)的逗号。语法错误将在}附近报告,但您需要更改{附近的一些内容,例如使用一元+或分号为 Perl 提供一些帮助

解决方案是在您发现时消除歧义。这些中的任何一个都可以工作

map +( 0 => $_ ), @hosts
map(( 0 => $_ ), @hosts)
map { +0 => $_ } @hosts
map { ( 0 => $_ ) } @hosts
map { ; 0 => $_ } @hosts

map有两种语法:

map BLOCK LIST   e.g. map { f() } g()
map EXPR, LIST   e.g. map f(), g()

当Perl遇到map时,它需要确定使用了哪种语法。假设 map 之后的第一个令牌是 { 。这就是区块的开始,对吧?坚持!表达式也可以以{开头!

my $hash_ref = { key => 'val' };

语法模棱两可。Perl 必须"猜测"你使用的是哪种语法。Perl 会提前查看下一个令牌来帮助猜测,但有时它仍然猜错了。这是其中一种情况。

以下是解决此问题的标准解决方法:

map {; ... } LIST    # Force Perl to recognize the curly as the start of a BLOCK
map +{ ... }, LIST   # Force Perl to recognize the curly as the start of a hash constructor
  • ;不能是哈希构造函数的一部分,因此{只能启动 BLOCK。
  • +必然启动一个 EXPR(而不是一个块)。在这种情况下,这是一个除了提供帮助之外什么都不做的操作员。

例如

map {; +{ $row->{id} => $row->{val} } } @rows

在 perldoc on map 中有描述: http://perldoc.perl.org/functions/map.html

简而言之,你应该使用像 parens 或 + -symbol 这样的小助手,这样 perl 就能够正确解析{...}构造:

my $r = someSubroutine( map { + 0 => $_ } @hosts)

最新更新