为什么 $foo->{bar} autovivify 而 %$foo 没有?

Why does $foo->{bar} autovivify but %$foo doesn't?

我有以下代码:

$headers;
some_sub( %$headers );

当我调用 some_sub 时出现错误:

Can't use an undefined value as a HASH reference at ...

但是类似的代码不会产生错误:

$headers->{ x };

为什么自动生成在第一个示例中的工作方式与在第二个示例中的工作方式不同?

UPD

我被 @ThisSuitIsBlackNot 注意到了。我真的问:

why my $h; $h->{foo} works and my $h; %$h doesn't

UPD
真实代码:

my $email =  Email::Simple->create(
    header =>  [
        To             =>  $address,
        From           =>  $cnf->{ from },
        Subject        =>  $subject,
        'Content-Type' =>  'text/html; charset="utf8"',
        %$headers,
    ],
    body => $body
);

%$hash 传递给子程序时绝对会自动生成。

$ perl -Mstrict -wE'my $foo; say $foo // "undef"'
undef

$ perl -Mstrict -wE'sub f { } my $bar; f(%$bar); say $bar // "undef"'
HASH(0x10b50e0)

错误消息来自 some_sub 中发生的其他事情,可能是 @_ 中的不正确分配。

注意 添加到问题中的代码演示了为什么没有发生自动生成。

Short 您的 sub 采用一个列表(散列),其中有一个匿名数组作为元素 - %$headers 被埋在该数组中。它是 匿名数组 这是标量的别名,因此不需要 %$headers 是可修改的。因此,不会发生自动激活,并且会出现如下所述的致命运行时错误,因为在未定义的引用上尝试取消引用。


A %$ref 左值上下文 中使用时自动激活。这可能发生在子调用中,见下文。

您显示的错误是由于使用了未定义的引用。例如,语句

my %hash = %{ $ref };

尝试从存储在 $ref 中的内存位置复制哈希并将其分配给 %hash。符号 %hash 是在编译时创建的,但是如果在 $ref 中没有找到散列或者 $ref 中没有任何内容,我们会得到一个错误。这里没有自动生成。 use strict 生效

perl -wE'use strict; my $h; my %h = %$h; say $h'

这会引发致命的运行时错误

Can't use an undefined value as a HASH reference at -e line 1.

eval-ed 生存下来时

perl -wE'use strict; my $h; my %h = eval { %$h }; say $h; say "hi"'

它打印一条关于“未初始化值”的警告,一个空行,然后是hi。没有哈希。

但是,当在子程序调用中用作参数时,它会自动激活

perl -wE'use strict; sub tt { 1 }; my $h; tt( %$h ); say $h'

因为这会打印行 HASH(0x257cd48),没有警告或错误。

左值上下文中使用取消引用的对象时会发生自动生成,这意味着它需要是可修改的。在子例程调用中,原因是函数的参数在 @_ 中有别名,因此必须可以修改它们。相同的别名需要使其在 foreach 循环中发生,而 keys 重置哈希迭代器。参见 this post and this post and this post

感谢 ThisSuitIsBlackNot 的解释和链接。

在您的情况下,%$ref 作为匿名数组的元素传递,因此没有别名(arrayref 本身是)。所以自动激活不会启动,你会得到那个错误。


自动激活 来自perlglossary

In Perl, storage locations (lvalues) spontaneously generate themselves as needed, including the creation of any hard reference values to point to the next level of storage. The assignment $a[5][5][5][5][5] = "quintet" potentially creates five scalar storage locations, plus four references (in the first four scalar locations) pointing to four new anonymous arrays (to hold the last four scalar locations). But the point of autovivification is that you don’t have to worry about it.

另见,例如,article from Effective Perler