What's the safest way to iterate through the keys of a Perl hash?

后端 未结 9 945
情深已故
情深已故 2020-12-22 20:31

If I have a Perl hash with a bunch of (key, value) pairs, what is the preferred method of iterating through all the keys? I have heard that using each may in s

相关标签:
9条回答
  • 2020-12-22 21:12

    I always use method 2 as well. The only benefit of using each is if you're just reading (rather than re-assigning) the value of the hash entry, you're not constantly de-referencing the hash.

    0 讨论(0)
  • 2020-12-22 21:14

    One thing you should be aware of when using each is that it has the side effect of adding "state" to your hash (the hash has to remember what the "next" key is). When using code like the snippets posted above, which iterate over the whole hash in one go, this is usually not a problem. However, you will run into hard to track down problems (I speak from experience ;), when using each together with statements like last or return to exit from the while ... each loop before you have processed all keys.

    In this case, the hash will remember which keys it has already returned, and when you use each on it the next time (maybe in a totaly unrelated piece of code), it will continue at this position.

    Example:

    my %hash = ( foo => 1, bar => 2, baz => 3, quux => 4 );
    
    # find key 'baz'
    while ( my ($k, $v) = each %hash ) {
        print "found key $k\n";
        last if $k eq 'baz'; # found it!
    }
    
    # later ...
    
    print "the hash contains:\n";
    
    # iterate over all keys:
    while ( my ($k, $v) = each %hash ) {
        print "$k => $v\n";
    }
    

    This prints:

    found key bar
    found key baz
    the hash contains:
    quux => 4
    foo => 1
    

    What happened to keys "bar" and baz"? They're still there, but the second each starts where the first one left off, and stops when it reaches the end of the hash, so we never see them in the second loop.

    0 讨论(0)
  • 2020-12-22 21:18

    The place where each can cause you problems is that it's a true, non-scoped iterator. By way of example:

    while ( my ($key,$val) = each %a_hash ) {
        print "$key => $val\n";
        last if $val; #exits loop when $val is true
    }
    
    # but "each" hasn't reset!!
    while ( my ($key,$val) = each %a_hash ) {
        # continues where the last loop left off
        print "$key => $val\n";
    }
    

    If you need to be sure that each gets all the keys and values, you need to make sure you use keys or values first (as that resets the iterator). See the documentation for each.

    0 讨论(0)
提交回复
热议问题