perl hash问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了perl hash问题相关的知识,希望对你有一定的参考价值。

1 #!/bin/usr/perl -w
2 use strict;
3
4 my %hash;
5 $hash1->1=0;
6 $hash1->2=0;
7 $hash1->3=0;
8
9 for my $key (keys %$hash1)
10 print "$key\n";
11
12
为什么结果是1 2 3,
3怎么没有把1.2覆盖掉呢?hash不是一一对应码?
hash1相当于key,怎么能指向3个value hash。

你所定义的%hash是一个值为哈希引用的哈希。

%hash的key为1,而值为1 => 0, 2 => 0, 3 => 0。这个花括号很重要,它表示这是一个匿名哈希,所以$hash1的值其实就是1 => 0, 2 => 0, 3 => 0,对于哈希引用来说,%是用来解引用的,也就是得到了一个(1 => 0, 2 => 0, 3 => 0)哈希,注意这里是圆括号。所以你调用keys函数的时候,返回的是(1,2,3)这个列表,打印出来的时候自然就是1,2,3了。
这里面有一些perl的数据结构的知识,总之,在perl里面,引用是个非常强大的东西,[],是用来生成匿名数组和哈希的,并返回它们的引用,而@[], %是用来解引用,得到里面的数据。可以用来构建复杂的数据结构,你可以去看看《perl技术内幕》,在这部分讲得不错。
my %hash = (
'1' =>
'1' => '0',
'2' => '0',
'3' => '0',

);
参考技术A 这个其实数据结构是这样的
my %hash = (
'1' =>
'1' => '0',
'2' => '0',
'3' => '0',



);

%hash 是一个哈希,$hash1 是hash中key为1时的value,而这个value是一个匿名哈希的引用
所以%$hash1 是相当于那个匿名hash ,在这个匿名哈希中有3个key1,2,3,打印出来当然是3个了。

Perl:while ($key = each %hash) 不会在 key = 0 处停止

【中文标题】Perl:while ($key = each %hash) 不会在 key = 0 处停止【英文标题】:Perl: while ($key = each %hash) doesn't stop at key = 0 【发布时间】:2010-09-18 06:21:31 【问题描述】:

显然,我不需要这个;我只是好奇这里发生了什么。我失踪了吗 简单的东西?我可以在所有版本的 Perl 中依赖这种行为吗?)

Perl v5.8.8:

%h = ( 0=>'zero', 1=>'one', 2=>'two' );
while ($k = each %h) 
    $v = delete $h$k;
    print "deleted $v; remaining: @h0..2\n";

输出

deleted one; remaining: zero  two
deleted zero; remaining:   two
deleted two; remaining:

man perlfunc(每个)没有解释为什么 当 $k 被赋值为 0 时,while 循环继续。 代码的行为就像while 循环中的条件一样 是($k = each %h, defined $k)

如果循环条件实际改为 ($k = each %h, $k) 确实如此 按预期停在$k = 0

它也停在$k = 0 用于以下 重新实现each

%h = ( 0=>'zero', 1=>'one', 2=>'two' );
sub each2 
    return each %$_[0];

while ($k = each2 \%h) 
    $v = delete $h$k;
    print "deleted $v; remaining: @h0..2\n";

只输出:

deleted one; remaining: zero  two

【问题讨论】:

【参考方案1】:

您在标量上下文中调用each,因此由于列表返回值而无法正常工作。

就像

while ($line = <FILE>)

是特殊情况下添加隐式defined,所以是

while ($key = each %hash)

在 5.8.8 中,这发生在 op.c,第 3760-3766 行:

case OP_SASSIGN:
  if (k1->op_type == OP_READDIR
      || k1->op_type == OP_GLOB
      || (k1->op_type == OP_NULL && k1->op_targ == OP_GLOB)
      || k1->op_type == OP_EACH)
    expr = newUNOP(OP_DEFINED, 0, expr);
  break;

我不确定这是否适用于所有版本的 Perl 5。

另见:When does while() test for defined vs truth 在 PerlMonks 上。我找不到 Perl 文档中提到的地方(提到了 &lt;FILE&gt; 案例,但我没有看到 each 案例)。

【讨论】:

【参考方案2】:

cjm 是对的。我只想补充一点,当遇到类似这样的奇怪事情时,通过B::Deparse 运行您的代码以了解 Perl 如何理解您的代码通常很有帮助。我也喜欢使用 -p 开关来显示优先级错误。

$ perl -MO=Deparse,p your_example.plx
(%h) = (0, 'zero', 1, 'one', 2, 'two');
while (defined($k = each %h)) 
    $v = delete $h$k;
    print "deleted $v; remaining: @h0..2\n";

your_example.plx syntax OK

【讨论】:

【参考方案3】:

谢谢,cjm。 很明显,某种隐式添加了 defined 对于 glob 来说就是这样,但不是在哪里 记录在案。现在至少我知道在有限的情况下 该特殊处理适用。

但是信息应该在 perlfunc 文档中, 不仅仅是 Perl 源代码!

【讨论】:

以上是关于perl hash问题的主要内容,如果未能解决你的问题,请参考以下文章

perl中 hash值是数组如何访问?谢谢

perl中如何判断一个hash是不是为空

Perl:在使用“严格引用”时不能使用字符串(“XXX”)作为 HASH 引用

如何在 Perl 中找到哈希中的键数?

Perl -- 使用 JSON::RPC::Client 时出现“不是 HASH 引用”错误

Perl:while ($key = each %hash) 不会在 key = 0 处停止