使用`each`迭代哈希不像预期的那样

时间:2016-03-06 14:28:32

标签: perl function hash iteration

我正在编写一个Perl脚本并编写了一个子程序来检查我的哈希中是否存在密钥。这是子程序的内容:

sub _check_existence {
    my $lib = $_[0];
    while( my( $key, $value ) = each (%{$MyHash{sub_keys}})) 
    {
        if ($key =~ $lib)
        {
            return 1;
        }   
    }
    return 0;    }

问题在于,每次运行该功能时,它都会从上次运行开始。

例如,如果哈希包含密钥0 1 2 3 4 5 6 {{1} } 7,第一次调用子程序寻找键8时它会找到它。但是,如果我再次调用子程序寻找3,我将得到 false ,因为迭代从3继续,而不是从开始。

有人可以解释导致这种情况的原因吗?

1 个答案:

答案 0 :(得分:4)

each存在一个问题,正如您所发现的那样,它会为记住迭代位置的每个哈希保留一个内部状态

您可以通过调用keys %MyHash来重置该状态,以便您的子程序变为

sub _check_existence {

    my ($lib) = @_;

    while ( my ( $key, $value ) = each %{ $MyHash{sub_keys} } ) {
        if ( $key =~ /$lib/ ) {
            keys %{ $MyHash{sub_keys} };
            return 1;
        }
    }

    return;
}

但是,您所编写的是一个子例程,它检查散列的任何键是否包含传递的参数作为子串,这是一个奇怪的要求。如果你的意思是检查是否相等那么你应该使用哈希的基本属性 - 它被其键索引,并且有一个内置的运算符:你可以写

exists $MyHash{sub_keys}{$_[0]};

如果你真的想要检查子字符串而不是简单的相等,那么还有另一种选择。您永远不会使用$value,因此您只需要提供哈希的列表。 keys运算符与each没有相同的问题,因为它不是设计为在标量上下文中每次调用时返回下一个键/值对。所以你可以写这个

sub _check_existence {

    my ($lib) = @_;

    for my $key ( keys %{ $MyHash{sub_keys} } ) {
        return 1 if $key =~ /$lib/;
    }

    return;
}

最后我会说在子程序中使用全局%MyHash有点难看。它应作为另一个子例程参数

通过引用传递