Связь:: Хеш имеет их:
sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
sub NEXTKEY { each %{$_[0]} }
NEXTKEY берет два аргумента, один из которых является последним ключом, но на тот аргумент никогда не ссылаются?
Различные документы Связи не проливают света на это кроме этого в perltie:
my $a = keys %{$self->{LIST}}; # reset each() iterator
рассмотрение документа для каждого не добавляет к этому.
Что продолжается?
В этом методе используется собственный метод 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}};
}
Вам нужно беспокоиться о втором аргументе 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}};
}