有没有办法让一个类重载数组解引用器,这样我就可以向foreach
提供该类的实例,并在每次迭代时运行自定义函数?
我试过了:
@{}
并将其分配给子。但是,在这种情况下,sub只执行一次,并且应该返回对要迭代的数组的引用。几乎但不完全是我想要的。<>
。这将在每次读取尝试时执行指定的功能。究竟我想要它,但它适用于while
循环而不是foreach
。overloading.评论
use overloaded;
$class = overloaded->new();
$class->add("Hi");
$class->add("Hello");
$class->add("Yeet");
foreach $string (@$class) {
print("NEXT ITEM: ".$string."\n");
}
while ($item = <$class>) {
print("NEXT ITEM: ".$item."\n");
}
overloaded.屏幕
package overloaded;
use strict;
use warnings;
use Data::Dumper;
use overload '@{}' => \&next, '<>' => \&fetchNext;
sub new {
my ($class, %args) = @_;
$args{fields} = ();
$args{pos} = 0;
return bless { %args }, $class;
}
sub add {
my ($self, $elem) = @_;
push(@{$self->{fields}}, $elem);
}
sub fetchNext {
my ($self) = @_;
print("reading next line...\n");
return $self->{fields}->[$self->{pos}++];
}
sub next {
my ($self) = @_;
print ("getting next array item\n");
return \@{$self->{fields}};
}
1;
输出:
$ perl overloading.pl
getting next array item
NEXT ITEM: Hi
NEXT ITEM: Hello
NEXT ITEM: Yeet
reading next line...
NEXT ITEM: Hi
reading next line...
NEXT ITEM: Hello
reading next line...
NEXT ITEM: Yeet
reading next line...
你在这里遇到的问题不是@{...}
和<...>
之间的区别,而是foreach
和while
之间的区别。
while
循环有点像迭代器,其执行方式如下所示:
while (you can run a piece of code and get back a value) {
do something
}
因此,每次循环时,它都会执行while
条件中的代码片段,并期望获得单个值。 while
条件中的代码在标量上下文中运行。
另一方面,foreach
循环只执行一次代码,并期望得到一个值列表。循环开始处括号之间的代码在列表上下文中执行。
这就是您使用以下方法一次读取大型文件的原因:
while (<$file_handle>) {
...
}
这一次只能从文件中读取一条记录。如果您使用foreach
循环而不是这样:
foreach (<$file_handle>) {
...
}
然后你会立刻从文件句柄中获取所有记录 - 显然,它会占用更多的内存。
取消引用数组引用也是这样的。您可以同时获得所有值。重写的方法(next()
)只会被调用一次,并且会返回一个值列表。
我在Object::Iterate展示了一些技巧。给你的对象一些方法来提供下一个值并从那里开始。
[这增加了Dave Cross的答案而不是自己的答案]
每个集合都有一个迭代器实例会导致各种问题。这就是为什么每个人都使用keys
而不是each
。因此,我强烈建议您的类生成一个迭代器而不是一个迭代器,如下所示:
package My::Collection;
use strict;
use warnings;
use Iterator::Simple qw( iarray );
sub new {
my ($class) = @_;
my $self = bless({}, $class);
$self->{fields} = [];
return $self;
}
sub add {
my ($self, $elem) = @_;
push @{ $self->{fields} }, $elem;
}
sub iter {
my ($self) = @_;
return iarray($self->{fields});
}
1;
使用方法如下:
use strict;
use warnings;
use feature qw( say );
use My::Collection qw( );
my $collection = My::Collection->new();
$collection->add("Hi");
$collection->add("Hello");
$collection->add("Yeet");
my $iter = $collection->iter();
while ( my ($item) = $iter->next() ) {
say $item;
}
您还可以使用以下任一更神奇的选项:
while ( my ($item) = $iter->() )
while ( my ($item) = <$iter> )