Perl哈希不能按预期工作

por*_*ton 2 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();
Run Code Online (Sandbox Code Playgroud)

上面的代码输出

$VAR1 = 'a';
$VAR2 = 1;
$VAR3 = 'b';
$VAR4 = 2;
$VAR5 = 'c';
$VAR6 = 3;
$VAR7 = 'd';
$VAR8 = 4;
Run Code Online (Sandbox Code Playgroud)

尽管我理解它应该输出

$VAR1 = {
          'a' => 1,
          'c' => 3,
          'b' => 2,
          'd' => 4
        };
Run Code Online (Sandbox Code Playgroud)

我的误会是什么?

Bor*_*din 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();
Run Code Online (Sandbox Code Playgroud)

产量

{ a => 1, b => 2, c => 3, d => 4 }
Run Code Online (Sandbox Code Playgroud)


ike*_*ami 7

Perl语言含糊不清.举个例子

sub some_sub {
   {  }     # Is this a hash constructor or a block?
}
Run Code Online (Sandbox Code Playgroud)

{ }是块的有效语法("裸循环").
{ }是哈希构造函数的有效语法.
两者都被允许作为声明!

所以Perl必须猜测.Perl通常猜对了,但并不总是这样.在你的情况下,它猜对了f(),但不是g().

要解决此问题,您可以提供Perl"提示".一元 - +可以用来做到这一点.一元+是一个完全透明的运营商; 它什么都不做.但是,必须后跟表达式(不是语句).{ }只有一种可能的含义作为表达.

+{ }   # Must be a hash constructor.
Run Code Online (Sandbox Code Playgroud)

同样,你可以欺骗Perl来猜测另一种方式.

{; }   # Perl looks ahead, and sees that this must be a block.
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下,你可以使用

sub g { +{
  %{f()},
  c => 3,
  d => 4,
} }
Run Code Online (Sandbox Code Playgroud)

要么

sub g { return {
  %{f()},
  c => 3,
  d => 4,
} }
Run Code Online (Sandbox Code Playgroud)

(return如果有的话,还必须跟一个表达式.)