3

我有以下代码:

$headers;
some_sub( %$headers );

当我打电话时,some_sub我得到一个错误:

不能在 ... 处使用未定义的值作为 HASH 引用

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

$headers->{ x };

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

UPD

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

为什么我的 $h; $h->{foo} 有效,我的 $h; %$h 没有

UPD
真实代码:

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

2 回答 2

5

%$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,可能是来自 的不正确分配@_

于 2016-12-30T18:58:14.803 回答
5

注意   添加到问题中的代码演示了为什么不会发生自动生存。

Short   你的 sub 接受一个列表(散列),它有一个匿名数组作为元素——并%$headers被埋在那个数组中。标量别名是匿名数组 ,因此不需要%$headers可修改。因此不会发生自动激活,并且您会收到下面描述的致命运行时错误,因为在未定义的引用上尝试取消引用。


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

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

my %hash = %{ $ref };

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

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

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

不能在 -e 第 1 行使用未定义的值作为 HASH 引用。

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'

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

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

感谢ThisSuitIsBlackNot的解释和链接。

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


perlglossary论自动生存

在 Perl 中,存储位置(左值)会根据需要自行生成,包括创建任何硬引用值以指向下一级存储。该分配$a[5][5][5][5][5] = "quintet"可能会创建五个标量存储位置,以及指向四个新匿名数组(用于保存最后四个标量位置)的四个引用(在前四个标量位置中)。但是自动复活的重点是您不必担心它。

也可以看看,例如,来自 Effective Perler 的一篇文章

于 2016-12-30T18:58:24.830 回答