2014-02-12 4 views
5

Я хочу получить элементы из списка, который хранится внутри класса 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; 

Когда я запускаю это, Лось называет строитель снова после вызова сброса() (то есть, тем яснее). Теперь мой вопрос: гарантировано ли это поведение? В документации не говорится.

(Набрав этот вопрос, я также начал задаваться вопросом: как вы думаете, это плохой дизайн? Мне нравится интерфейс, похожий на итератор, очень элегантный на вызывающей стороне и прост в реализации. что дизайн не годится?)

+0

Возможно, вы должны сказать, что в #moose на irc.perl.org. Люди, ответственные за Муз, будут знать лучше всего. – simbabque

ответ

7

Да, если ленивый атрибут был очищен, то при следующем вызове аксессора значение будет восстановлено.

Очистка _data в основном подобный делать delete($self->{_data}). Или было бы, если бы объекты Moose были hashrefs, но они не hashrefs, они - объекты. (На самом деле, они являются hashrefs, но часть опыта Moose заключается в том, что мы должны притворяться, что не знаем этого. Мигающая сторона.)

Lazy attributes использует exists($self->{_data}), чтобы решить, нужно ли это значение строить ,

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

Обновление: Вы правы, что это не задокументировано очень хорошо.