为什么Perl认为存在不存在的多级散列元素?
抱歉,这似乎是一个基本问题,但我仍然不明白。例如,如果我有一个哈希:
my %md_hash = ();
$md_hash{'top'}{'primary'}{'secondary'} = 0;
为什么这是真的?
if ($md_hash{'top'}{'foobar'}{'secondary'} == 0) {
print "I'm true even though I'm not in that hash\n";
}
哈希中没有“foobar”级别,所以这不会导致错误吗?
TIA
Sorry, this seems like such a basic question but I still don't understand. If I have a hash, for example:
my %md_hash = ();
$md_hash{'top'}{'primary'}{'secondary'} = 0;
How come this is true?
if ($md_hash{'top'}{'foobar'}{'secondary'} == 0) {
print "I'm true even though I'm not in that hash\n";
}
There is no "foobar" level in the hash so shouldn't that result in false?
TIA
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这不是多维哈希特定的问题。
它的工作原理与
$foo{'bar'}
is undef 相同,它将 true 与 0 进行比较,但如果您按照应有的方式启用了警告,则会出现警告。
您的情况还有一个额外的副作用;当您说
$md_hash{'top'}
返回哈希引用时,会在该哈希中查找 'foobar' 键。由于{'secondary'}
,'foobar' 元素查找位于哈希取消引用上下文中。这使得$md_hash{'top'}{'foobar'}
“autovivify” 成为 'foobar' 键的值的哈希引用,留下这样的结构:autovivification pragma 可用于禁用此行为。人们有时断言exists()对自动视觉化有一些影响,但事实并非如此。
This isn't a multidimensional hash specific question.
It works the same with
$foo{'bar'}
is undef, which compares true to 0, albeit with a warning if you have warnings enabled as you should.There is an additional side effect in your case; when you say
$md_hash{'top'}
returns a hash reference, and the 'foobar' key is looked for in that hash. Because of the{'secondary'}
, that 'foobar' element lookup is in hash-dereference context. This makes$md_hash{'top'}{'foobar'}
"autovivify" a hash reference as the value of the 'foobar' key, leaving you with this structure:The autovivification pragma can be used to disable this behavior. People sometimes assert that exists() has some effect on autovifification, but this is not true.
您正在测试数字零的未定义值。当然你会得到真实的结果!你在期待什么?
您还应该在
使用警告
下收到警告。你为什么不呢?如果你不开始一个程序:
你真的不应该打扰。 :)
编辑
即使在 CPAN
autovivification
模块下,也没有任何变化。证人:运行时,显示:
测试是
==
运算符。它的 RHS 是0
。它的 LHS 是undef
与自动生存无关。由于undef
的数字为0
,这意味着 LHS 和 RHS 都包含0
,==
可以正确识别因为持有相同的号码。自动生存不是这里的问题,正如 ysth 在写道“这不是一个多维哈希特定问题”时正确观察到的那样。重要的是您传递给
==
的内容。undef
的数字是0
。如果您真的非常想的话,可以通过使用 CPAN 编译指示来停止 autoviv。但你永远无法通过抑制 autoviv 来改变这里发生的情况。这表明这根本不是一个 autoviv 问题,而只是一个 undef 问题。
现在,当您执行此操作时,您将获得“额外”键,因为未定义的左值将在通过取消引用链的过程中被填充。它们必然是相同的:
每当您在 Perl 中 deref 一个左值
undef
时,该存储位置总是被填充为对新分配的匿名引用的正确类型的引用正确的类型。简而言之,它会自动生存。你可以通过抑制或回避自动生存来停止。然而,拒绝 autoviv 与回避它并不相同,因为你只是改变了返回的内容。整体表达仍然得到充分评估:不存在自动短路仅仅因为你抑制了autoviv。那是因为 autoviv 不是问题(如果它不存在,你会真的很生气:相信我)。
如果你想短路,你必须自己写。我似乎从来不需要自己。在 Perl 中,就是这样。另一方面,C 程序员非常习惯于编写
And,所以如果您愿意,您也可以这样做。然而,以我自己的经验来看,这种情况相当罕见。在 Perl 中,您几乎必须竭尽全力才能发挥作用,因为很容易安排您的代码不在存在空级别时改变其行为方式。
You are testing an undefined value for numeric zero. Of course you get a true result! What were you expecting?
You should also get a warning under
use warnings
. Why didn’t you?If you do not start a program with:
you really shouldn’t even bother. :)
EDIT
Even under the CPAN
autovivification
module, nothing changes. Witness:When run, that says:
The test is the
==
operator. Its RHS is0
. Its LHS isundef
irrespective of autovivification. Sinceundef
is numerically0
, that means that both LHS and RHS contain0
, which the==
correctly identifies as holding the same number.Autovivification is not the issue here, as ysth correctly observes when he writes that “This isn’t a multidimensional hash specific question.” All that matters is what you pass to
==
. Andundef
is numerically0
.You can stop autoviv if you really, really want to — by using the CPAN pragma. But you will not ever manage to change what happens here by suppressing autoviv. That shows that it is not an autoviv matter at all, just an
undef
one.Now, you will get “extra” keys when you do this, since the undefined lvalue will get filled in on the way through the dereference chain. These are neccesarily all the same:
Whenever you deref an lvaluable
undef
in Perl, that storage location always gets filled in with the proper sort of reference to a newly allocated anonymous referent of the proper type. In short, it autovivs.And that you can stop either by suppressing or else by sidestepping the autoviv. However, denying the autoviv is not the same as sidestepping it, because you just change what sort of thing gets returned. The overall expession is still fully evaluated: there is no automatic short-circuiting just because you suppress autoviv. That’s because autoviv is not the problem (and if it were not there, you would be really annoyed: trust me).
If you want short-circuiting, you have to write that yourself. I never seem to need to myself. In Perl, that is. On the other hand, C programmers are quite accustomed to writing
And so you can do that, too, if you want to. However, it is pretty rare in my own experience. You almost have to bend over wrongwards in Perl for that ever to make a difference, as it is quite easy to arrange for your code not to change how it acts if there are empty levels.
尝试搜索“Perl autovivification”。
当您第一次访问哈希值时,它们就会“突然出现”。在本例中,该值为
undef
,当解释为数字时为零。要测试哈希值是否存在而不自动激活它,请使用
exists
运算符:请注意,这仍会自动激活
$md_hash{'top'}
并且$md_hash{'top'}{'foobar'}
(即子哈希)。[编辑]
正如 tchrist 在评论中指出的那样,将
undef
与任何东西进行比较都是糟糕的风格。因此,编写此代码的更好方法是:(尽管这现在将自动激活嵌套哈希的所有三个级别,并将最低级别设置为
undef
'。)Try a search on "Perl autovivification".
The hash values "spring into existence" when you first access them. In this case, the value is
undef
, which when interpreted as a number is zero.To test for existence of a hash value without auto-vivifying it, use the
exists
operator:Note that this will still auto-vivify
$md_hash{'top'}
and$md_hash{'top'}{'foobar'}
(i.e. the sub-hashes).[edit]
As tchrist points out in a comment, it is poor style to compare
undef
against anything. So a better way to write this code would be:(Although this will now auto-vivify all three levels of the nested hash, setting the lowest level to
undef
'.)