Perl哈希无法正常工作

时间:2018-07-31 12:18:55

标签: perl hashmap perl5

#!/usr/bin/perl

sub f { {
  a => 1,
  b => 2
} }

sub g { {
  %{f()},
  c => 3,
  d => 4,
} }

use Data::Dumper;
print Dumper g();

上面的代码输出

$VAR1 = 'a';
$VAR2 = 1;
$VAR3 = 'b';
$VAR4 = 2;
$VAR5 = 'c';
$VAR6 = 3;
$VAR7 = 'd';
$VAR8 = 4;

尽管我认为它应该输出

$VAR1 = {
          'a' => 1,
          'c' => 3,
          'b' => 2,
          'd' => 4
        };

我的误会是什么?

2 个答案:

答案 0 :(得分:9)

问题在于,Perl中的一对大括号不明确,可能是一个块或一个匿名哈希

由于您g中的哈希内容(请使用更好的名称),perl假设您正在编写一个代码块,它只是一个标量值列表

像这样使它更加明确,您的代码将按预期运行

use strict;
use warnings 'all';

sub foo {
    {
        a => 1,
        b => 2,
    }
}

sub bar {
    my $href = {
        %{ foo() },
        c => 3,
        d => 4,
    }
}

use Data::Dump;
dd bar();

输出

{ a => 1, b => 2, c => 3, d => 4 }

答案 1 :(得分:7)

Perl语言有歧义。举个例子

sub some_sub {
   {  }     # Is this a hash constructor or a block?
}

{ }是一个块(“裸循环”)的有效语法。
{ }是哈希构造函数的有效语法。
两者都可以声明!

因此Perl必须猜测。 Perl通常猜测正确,但并非总是如此。对于您来说,它对于f()正确猜出了,但对g()却猜不出来。

要解决此问题,可以为Perl提供“提示”。一元-+可用于执行此操作。一元-+是一个完全透明的运算符;它什么都不做。但是,必须在其后跟随一个表达式(而不是语句)。 { }仅具有一种可能的含义。

+{ }   # Must be a hash constructor.

类似地,您可以欺骗Perl进行另一种猜测。

{; }   # Perl looks ahead, and sees that this must be a block.

因此,在这种情况下,您可以使用

sub g { +{
  %{f()},
  c => 3,
  d => 4,
} }

sub g { return {
  %{f()},
  c => 3,
  d => 4,
} }

({return之后还必须带有表达式。)