Я могу прыгать, как это?


В моем вложенные в петли ниже, иногда необходимо для выхода из внешнего цикла, а затем продолжить выполнение программы. Поскольку контур наклейки и прочие Гото-как конструкции сильно обескуражен, я немного боялся Раптора. Это использование ОК? Есть ли лучший способ структурировать программу?

my @objects = load_objects();
OUTER: for my $obj ( @objects ) {
    for my $element ( @{$obj->elements} ) {
        if ( is_case_1( $element ) ) {
            ...
        } elsif ( is_case_2( $element ) ) {
            ...
        } else {
            warn "invalid element: $element";
            last OUTER;
        }
        stuff_that_assumes_valid_element( $element );
    }
    stuff_that_assumes_valid_object( $obj );
}
store_objects( @objects );


268
3
задан 24 апреля 2011 в 08:04 Источник Поделиться
Комментарии
2 ответа

У меня есть два замечания. Первый заключается в использовании этикетки. Второй-о том, почему вам может потребоваться исключение, а не логический тест.

Метки Циклов

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

@rassieс точки, что тесты должны быть инкапсулированы в is_valid() метод для ваших объектов-это прекрасно, но я хочу прокомментировать еще один важный аспект использования циклов с метками: именования.

Используя внешний как метка, как с помощью %хэш - переменной. Название говорит ремонт программиста ничего о том, что происходит или почему.

Синтаксис Perl требует существительное-глагол структура именования меток с ключевыми словами, как следующий и последний. Хорошие имена для вашего внешнего цикла может быть OBJECT_TEST, OBJECT_VALIDATION, или OBJECT_CHECK.

Исключения

Когда я смотрю на ваш код, я вижу структуру, которая ориентирована на обычном случае. Это нормально до тех пор, пока у вас есть способ, чтобы убедиться, что ошибок не поймали.

Если ваши stuff_that_assumes_valid_object() способ проверки на достоверность, а затем выбрасывает исключение (через умереть), то ваш код становится очень просто.

Этот код идентичен свой вложенный цикл:

 eval { $_->stuff_that_dies_on_invalid_object() for @objects }; 
store_objects(@objects);

Но если вы хотите, чтобы поведение в @rassieс кодом отсеивая недопустимые объекты и только хранения действительны те, которые вы можете сделать:

my @to_store = grep {
eval { $_->stuff_that_dies_on_invalid_object; 1 }
} @objects;
store_objects(@to_store);

Это также приятно знать, что ваши призывы к тому, что код делает предположения будут в безопасности. Либо вас ожидают неудачи и поймать исключение, или ваша программа завершается на неожиданный, небезопасную операцию.

П. С. @rassie абсолютно прав о Закон Деметры. Держать ваши внутренности объекта и знания о них как можно. Рассмотреть вопрос о внесении store_objects(), assumes_valid_elements() и assumes_valid_objects() код в методы.

3
ответ дан 30 мая 2011 в 06:05 Источник Поделиться

В общем, код ОК, т. е. я не думаю, что это должно быть изменено. Однако, чтобы повысить ясность, я бы сделал пару вещей по другому:

Это, наверное, лучше написать is_valid() метод для ваших объектов, так что весь внутренний цикл выполняется за один вызов функции. Затем, вы можете использовать команду grep , чтобы сократить внешний цикл вроде этого:

    my @objects = load_objects();
my @valid_objects = grep { $_->is_valid() } @objects;
stuff_that_assumes_valid_object($_) for @valid_objects;
store_objects(@valid_objects);

Также, в зависимости от того, что stuff_that_assumes_valid_element произойдет, вы можете либо положить, что звонок в is_valid() или в stuff_that_assumes_valid_object. В любом случае, ваш топ-уровня код работает с объектами и, следовательно, не слишком много знаю об одном элементов внутри этих объектов, это то, что объект сам должен знать и делать (см. закон Деметры для рассуждения).

3
ответ дан 24 апреля 2011 в 02:04 Источник Поделиться