Есть ли andand для Perl? - PullRequest
       31

Есть ли andand для Perl?

4 голосов
/ 08 января 2009

Я бы лучше сделал это:

say $shop->ShopperDueDate->andand->day_name();

против. это:

say $shop->ShopperDueDate->day_name() if $shop->ShopperDueDate;

Есть идеи?

(Эта идея основана на расширениях Ruby и .)

(На самом деле он вдохновлен Groovy, но большинство людей этого не знает; -)

обновление : Я думаю, что возможно и (), и eval {} - это хорошие решения. Это не рубин, поэтому я не могу ожидать, что все методы / функции будут прочитаны слева направо, так что, возможно, это может помочь. И тогда, конечно, Eval действительно является Perl способ сделать это.

Ответы [ 4 ]

9 голосов
/ 08 января 2009

Полагаю, ваш второй пример должен быть лучше:

say $shop->ShopperDueDate ? $shop->ShopperDueDate->day_name() : undef;

вместо того, что на самом деле говорит.

В любом случае, вы не можете сделать это с точно с этим синтаксисом без исходного фильтра, потому что undef не объект, а унарный оператор, поэтому у него не может быть никаких методов.

Вместо этого рассмотрим это:

package noop; 
our $maybe = bless [], 'noop';
sub AUTOLOAD { undef };

Этот $noop::maybe является объектом; все его методы возвращают undef. В другом месте у вас будет обычная функция, подобная этой:

sub maybe { $_[0] || $noop::maybe; }

Тогда вы можете написать это:

say maybe($shop->ShopperDueDate)->day_name()

Это работает, потому что "Maybe" возвращает свой аргумент, если true, в противном случае он возвращает наш $noop::maybe объект, который имеет методы, которые всегда возвращают undef.

РЕДАКТИРОВАТЬ : Исправление! Синтаксис ->andand-> можно иметь без фильтра источника, используя XS , который смешивается с внутренностями Perl. Леон Тиммерманс сделал реализацию, которая идет по этому пути. Он заменяет функцию undef() во всем мире, поэтому, скорее всего, он будет намного медленнее, чем мой метод.

9 голосов
/ 08 января 2009

Вы можете использовать оператор Perl eval для перехвата исключений, в том числе от попыток вызова методов с неопределенным аргументом:

eval {
    say $shop->ShopperDueDate->day_name();
};

Поскольку eval возвращает последний оцененный оператор или undef при ошибке, вы можете записать название дня в переменную следующим образом:

my $day_name = eval { $shop->ShopperDueDate->day_name(); };

Если вы действительно хотите проверить исключение, вы можете посмотреть в специальной переменной $@. Обычно это будет простая строка для встроенных исключений Perl, но может быть полным объектом исключения, если исключение происходит из autodie или другого кода, который использует исключения объекта.

eval {
    say $shop->ShopperDueDate->day_name();
};

if ($@) {
    say "The error was: $@";
}

Также возможно связать воедино последовательность команд, используя блок eval. Следующее будет только проверять, если это выходные, при условии, что у нас не было никаких исключений при поиске $day_name.

eval {
    my $day_name = $shop->ShopperDueDate->day_name();

    if ($day_name ~~ [ 'Saturday', 'Sunday' ] ) {
        say "I like weekends";
    }
};

Вы можете думать о eval как о try из других языков; действительно, если вы используете модуль Error из CPAN, вы можете даже записать его по буквам try. Стоит также отметить, что блочная форма eval (которую я демонстрировал выше) не сопровождается снижением производительности и компилируется вместе с остальным кодом. Строковая форма eval (которую я не показал) - это совершенно другой зверь, и его следует использовать с осторожностью, если он вообще есть.

eval технически считается оператором в Perl и, следовательно, является одним из немногих мест, где вы увидите точку с запятой в конце блока. Это легко забыть, если вы не используете eval регулярно.

Пол

4 голосов
/ 08 января 2009

Я думаю, что только что написал это. Я только что загрузил его в CPAN, вы можете найти его здесь .

0 голосов
/ 08 января 2009

Что-то вроде (не проверено):

use Object::Generic::False;
sub UNIVERSAL::andand { $_[0] || Object::Generic::False->false }

UNIVERSAL автоматически является подклассом всех других классов, так что это обеспечивает andand для всех объектов. (Очевидно, что создание методов в UNIVERSAL может привести к конфликтам или неожиданным действиям на расстоянии, поэтому его не следует использовать небрежно.) Если объект, для которого вызывается метод andand, имеет значение true, вернуть его; в противном случае возвращает универсальный ложный объект, который возвращает себя для любого вызова метода, используемого для него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...