Обязан ли лось снова звонить строителю после звонка в клинер?
Я хочу извлечь элементы из списка, который хранится внутри класса 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;
Когда я запускаю это, лось снова вызывает builder после вызова reset () (то есть clearer). Теперь мой вопрос: гарантировано ли такое поведение? В документации ничего не сказано.
(набирая этот вопрос, я также начал задаваться вопросом: как вы думаете, это плохой дизайн? Мне нравится итераторный интерфейс, очень элегантный на стороне вызова и простой в реализации. Но является ли этот самый вопрос признаком того, что дизайн разве это не хорошо?)
1 ответ:
Да, если атрибут lazy был очищен,то при следующем вызове метода доступа значение будет перестроено.
Очистка
_data
по существу похожа на выполнениеdelete($self->{_data})
. Или это было бы, если бы объекты Moose были хешрефами, но они не хешрефы, они объекты. (На самом деле это хашрефы, но часть опыта лося заключается в том, что мы должны притворяться, что не знаем этого. Подмигивающее лицо.)Ленивые атрибуты используют
exists($self->{_data})
для того, чтобы решить, должно ли значение быть построенный.Я не думаю, что это плохой дизайн, но если массив большой, то сохранение копии в
_data
, чтобы итеративно уничтожить сshift
, потенциально тратит память. Вы можете просто держать счетчик, где вы находитесь в массиве, и увеличивать его каждый раз.Update: Вы правы, что это не очень хорошо документировано.