Как делают Perl работа NEXTKEY и FIRSTKEY

Связь:: Хеш имеет их:

sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
sub NEXTKEY  { each %{$_[0]} }

NEXTKEY берет два аргумента, один из которых является последним ключом, но на тот аргумент никогда не ссылаются?

Различные документы Связи не проливают света на это кроме этого в perltie:

my $a = keys %{$self->{LIST}};      # reset each() iterator

рассмотрение документа для каждого не добавляет к этому.

Что продолжается?

6
задан mmccoo 9 June 2010 в 23:33
поделиться

2 ответа

В этом методе используется собственный метод each, позволяющий выполнять итерацию по отсортированному хешу более одного раза. Тем не менее, все стандартные правила, запрещающие добавлять или удалять ключи, остаются в силе. Было бы тривиально добавить предупреждение о том, что итераторы все еще используются при вызове STORE или DELETE .

#!/usr/bin/perl

use strict;
use warnings;

my $i = 0;
tie my %h, "HASH::Sorted", map { $_ => $i++ } "a" .. "g";

for my $key (keys %h) {
    print "$key => $h{$key}\n";
}
print "\n";

my $first = each %h;
print "first $first => $h{$first}\n";

my ($second_key, $second_value) = each %h;
print "second $second_key => $second_value\n";

print "\nall of them again:\n";
for my $key (keys %h) {
    print "$key => $h{$key}\n";
}

print "\nmultiple iterators\n";

my $o = tied %h;
while (my ($k, $v) = $o->each("outer")) {
    print "$k => $v\n";

    while (my ($k, $v) = $o->each("inner")) {
        print "\t$k => $v\n";
    }
}

print "\nhybrid solution\n";
while (my ($k, $v) = each %h) {
    print "$k => $v\n";

    #the iter_name is an empty string
    while (my ($k, $v) = $o->each) {
        print "\t$k => $v\n";
    }
}


package HASH::Sorted;

sub each {
    my ($self, $iter_name) = (@_, "DEFAULT");

    #each has not been called yet for this iter
    unless (exists $self->{_iters}{$iter_name}) {
        $self->{_iters}{$iter_name} = [ sort keys %{$self->{_hash}} ];
    }

    #end of list
    unless (@{$self->{_iters}{$iter_name}}) {
        delete $self->{_iters}{$iter_name};
        return;
    }

    my $key = shift @{$self->{_iters}{$iter_name}};

    if (wantarray) {
        return $key, $self->{_hash}{$key};
    }

    return $key;
}

sub TIEHASH {
    my $class = shift;

    return bless {
        _hash => { @_ },
        _iters => {},
    }, $class;
}

sub FETCH {
    my ($self, $key) = @_;

    return $self->{_hash}{$key};
}

sub STORE {
    my ($self, $key, $value) = @_;

    return $self->{_hash}{$key} = $value;
}

sub DELETE {
    my ($self, $key) = @_;

    return delete $self->{_hash}{$key};
}

sub CLEAR {
    my $self = shift;

    %{$self->{_hash}} = ();
}

sub EXISTS {
    my ($self, $key) = @_;

    return exists $self->{_hash}{$key};
}

sub FIRSTKEY {
    my $self = shift;

    #build iterator     
    $self->{_list} = [ sort keys %{$self->{_hash}} ];    

    return $self->NEXTKEY;
}

sub NEXTKEY {
    my $self = shift;

    return shift @{$self->{_list}};
}

sub SCALAR {
    my $self = shift;
    return scalar %{$self->{_hash}};
}
1
ответ дан 9 December 2019 в 20:40
поделиться

Вам нужно беспокоиться о втором аргументе NEXTKEY, только если вас интересует, к какому ключу обращались последним. По умолчанию хэши не заботятся о порядке, поэтому он не используется.

Что касается второй части, то функция keys в скалярном контексте возвращает количество элементов в хэше. Любой вызов keys сбрасывает итератор, используемый keys и each потому что он исчерпывает итератор.

Вызов keys на самом деле является вызовом FIRSTKEY и вызовом NEXTKEY, пока не останется элементов, которые не были возвращены.

Вызов каждого - это вызов FIRSTKEY (если FIRSTKEY еще не был вызван) или вызов NEXTKEY (если FIRSTKEY был вызван).

#!/usr/bin/perl

use strict;
use warnings;

my $i = 0;
tie my %h, "HASH::Sorted", map { $_ => $i++ } "a" .. "g";

for my $key (keys %h) {
    print "$key => $h{$key}\n";
}
print "\n";

my $first = each %h;
print "first $first => $h{$first}\n";

my ($second_key, $second_value) = each %h;
print "second $second_key => $second_value\n";

print "\nall of them again:\n";
for my $key (keys %h) {
    print "$key => $h{$key}\n";
}

package HASH::Sorted;

sub TIEHASH {
    my $class = shift;

    return bless { _hash => { @_ } }, $class;
}

sub FETCH {
    my ($self, $key) = @_;

    return $self->{_hash}{$key};
}

sub STORE {
    my ($self, $key, $value) = @_;

    return $self->{_hash}{$key} = $value;
}

sub DELETE {
    my ($self, $key) = @_;

    return delete $self->{_hash}{$key};
}

sub CLEAR {
    my $self = shift;

    %{$self->{_hash}} = ();
}

sub EXISTS {
    my ($self, $key) = @_;

    return exists $self->{_hash}{$key};
}

sub FIRSTKEY {
    my $self = shift;

    #build iterator     
    $self->{_list} = [ sort keys %{$self->{_hash}} ];    

    return $self->NEXTKEY;
}

sub NEXTKEY {
    my $self = shift;

    return shift @{$self->{_list}};
}

sub SCALAR {
    my $self = shift;
    return scalar %{$self->{_hash}};
}
11
ответ дан 9 December 2019 в 20:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: