我想从存储在Moose类中的列表中获取元素。该类知道如何填充该列表本身。它有点像迭代器,除了我希望能够重置迭代器,并开始从该列表中获取相同的元素,就好像我还没有这样做。我打算如下打电话:
while( my $slotlist = $class->get_next_slotlist ) {
# do something with $slotlist
}
除此之外,正如我所说,我可能希望稍后再次重申相同的内容:
$class->reset_slotlists;
while( my $slotlist = $class->get_next_slotlist ) {
# do something with $slotlist
}
我想过按照以下精简版(模拟)版本来设计类:
package List;
use Moose;
has '_data' => (
traits => [ 'Array' ],
is => 'ro',
predicate => 'has_data',
lazy => 1,
builder => '_build_data',
clearer => 'reset',
handles => {
next => 'shift',
},
);
sub _build_data { [ 'abc', 'def' ] }
package main;
use strict;
use warnings;
use Test::More;
use Test::Pretty;
my $list = List->new;
ok ! $list->has_data;
is $list->next, 'abc';
is $list->next, 'def';
is $list->next, undef;
is $list->next, undef;
$list->reset;
is $list->next, 'abc', 'Moose calls builder again after clearing';
is $list->next, 'def';
is $list->next, undef;
is $list->next, undef;
ok $list->has_data;
done_testing;
当我运行它时,Moose在调用reset()之后再次调用构建器(即更清晰)。我的问题是:这种行为有保证吗?文档没有说明。
(在输入这个问题时,我也开始疑惑:你认为这是不好的设计吗?我喜欢类似迭代器的界面,在调用方面非常优雅,并且易于实现。但是这个问题是一个标志,设计不好?)
答案 0 :(得分:7)
是的,如果已清除延迟属性,则下次调用访问者时,将重建该值。
清除_data
基本上就像在做delete($self->{_data})
一样。或者如果Moose对象是hashrefs,但它们不是hashrefs,它们是对象。 (实际上它们是下面的hashrefs,但是Moose体验的一部分是我们应该假装我们不知道那个。眨眼的脸。)
延迟属性使用exists($self->{_data})
来决定是否需要构建值。
我不认为这是一个糟糕的设计,但如果数组很大,那么在_data
中保留副本以使用shift
迭代销毁可能会浪费内存。您可以只保留一个计数器,使其在数组中的位置并每次递增。
更新:您说得对,这是非常好的。