为什么 $foo

编程入门 行业动态 更新时间:2024-10-27 11:24:57
本文介绍了为什么 $foo->{bar} 自动激活而 %$foo 没有?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有以下代码:

$headers;some_sub(%$headers);

当我调用 some_sub 时出现错误:

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

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

$headers->{ x };

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

UPD

我由 @ThisSuitIsBlackNot 指出.我真的想问:

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

UPD真正的代码:

my $email = Email::Simple->create(标题 =>[到 =>$地址,从 =>$cnf->{ from },主题 =>$主题,'内容类型' =>'文本/html;字符集="utf8"',%$标题,],身体 =>$body);

解决方案

注意 添加到问题中的代码说明了为什么不会发生自动激活.

短 你的子接受一个列表(哈希),它有一个匿名数组作为元素–并且 %$headers 被埋在该数组中.它是 anon 数组这是别名为的标量,因此不需要 %$headers 是可修改的.因此不会发生自动激活,并且您会收到下面描述的致命运行时错误,因为尝试对未定义的引用进行解引用.

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

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

my %hash = %{ $ref };

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

perl -wE'use strict;我的 $h;我的 %h = %$h;说 $h'

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

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

当 eval-ed 存活

perl -wE'use strict;我的 $h;我的 %h = eval { %$h };说 $h;打招呼"'

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

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

perl -wE'use strict;子 tt { 1 };我的 $h;tt(%$h);说 $h'

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

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

感谢 ThisSuitIsBlackNot 的解释和链接.

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

关于 autovivification 来自 perlglossary

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

另请参阅,例如,来自 Effective Perler 的文章

I have the following code:

$headers; some_sub( %$headers );

When I call some_sub I get an error:

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

But similar code does not produce an error:

$headers->{ x };

Why doesn't autovivification work the same way in the first example as it does in the second?

UPD

I noted by @ThisSuitIsBlackNot. I really ask:

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

UPD The real code:

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

解决方案

Note Code added to the question demostrates why autovivification doesn't happen.

Short Your sub takes a list (hash) which has an anonymous array as an element – and %$headers is buried in that array. It is the anon array that is the scalar aliased to, thus there is no requirement for %$headers to be modifiable. Thus no autovivification happens, and you get the fatal runtime error described below, as dereferencing is attempted on an undefined reference.

A %$ref autovivifies when used in lvalue context. This may happen in a sub call, see below.

The error you show is due to the use of an undefined reference. For example, the statement

my %hash = %{ $ref };

attempts to copy a hash from the memory location stored in $ref and assign it to %hash. The symbol %hash is created at compile time, but if no hash is found at $ref or if there is nothing in $ref, we get an error. No autovivification happens here. With use strict in effect

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

this throws the fatal runtime error

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

When eval-ed to survive that

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

it prints a warning about "uninitialized value", an empty line, and then hi. No hash.

However, when used as an argument in a subroutine call it autovivifies

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

as this prints the line HASH(0x257cd48), without warnings or errors.

The autovivification happens when a dereferenced object is used in lvalue context, which means that it needs to be modifiable. In a subroutine call the reason for this is that arguments to a function are aliased in @_ so it must be possible to modify them. The same aliasing need makes it happen in a foreach loop, while keys resets the hash iterator. See this post and this post and this post.

Thanks to ThisSuitIsBlackNot for explanation and links.

In your case the %$ref is passed as an element of an anonymous array, and is thus not aliased (the arrayref itself is). So autovivication does not kick in and you get that error.

On autovivification from 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.

Also see, for example, an article from Effective Perler

更多推荐

为什么 $foo

本文发布于:2023-10-16 15:52:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1498030.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:foo

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!