为什么$ foo-> {bar} autovivify但%$ foo不会?

时间:2016-12-30 18:25:47

标签: perl

我有以下代码:

$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
);

2 个答案:

答案 0 :(得分: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中的其他内容,可能是来自@_的错误分配。

答案 1 :(得分:5)

注意问题中添加的代码说明了为什么不进行自动更新。

你的sub采用一个列表(hash),它有一个匿名数组作为元素 - %$headers被隐藏在那个数组中。它是 anon数组 这是标量别名,因此不需要%$headers可修改。因此,不会发生自动更新,并且您将获得下面描述的致命运行时错误,因为尝试对未定义的引用进行解除引用。

%$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 - 生存时

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 postthis post以及this post

感谢ThisSuitIsBlackNot的解释和链接。

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

来自perlglossary

autovivification
  

在Perl中,存储位置(左值)会根据需要自发生成自己,包括创建任何硬参考值以指向下一级存储。赋值$a[5][5][5][5][5] = "quintet"可能会创建五个标量存储位置,以及四个引用(在前四个标量位置中)指向四个新的匿名数组(用于保存最后四个标量位置)。但自动更新的关键是你不必担心它。

另请参阅,例如article from Effective Pearler