【问题标题】:Iterating on hash using `each` not like expected使用 `each` 对哈希进行迭代不像预期的那样
【发布时间】:2016-03-06 14:28:32
【问题描述】:

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

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

问题是函数每次运行时都会从上次运行时开始。

例如,如果哈希有键012345678,则第一次调用子例程寻找键3 它会找到它。但是如果我再次调用子例程来寻找3,我会得到false,因为迭代从4 继续,而不是从头开始。

谁能解释一下是什么原因造成的?

【问题讨论】:

  • $key =~ $lib 通常会测试$key *是否包含$lib中的子字符串。它也将做一些奇怪的事情,如果$lib包含任何正则表达式元字符\ 987654339 ( 987654341 [ 987654343 ^ 987654345 * 987654347 ?.。您可能只想测试字符串相等$key eq $lib

标签: perl function hash iteration


【解决方案1】:

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 有点难看。它应该作为另一个子程序参数通过引用传递

【讨论】:

    猜你喜欢
    • 2014-06-23
    • 2014-06-18
    • 2023-03-04
    • 2017-04-11
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 2015-06-19
    • 2021-12-10
    相关资源
    最近更新 更多