Есть ли andand для Perl?
Я бы предпочел сделать это:
say $shop->ShopperDueDate->andand->day_name();
против этого:
say $shop->ShopperDueDate->day_name() if $shop->ShopperDueDate;
Есть идеи?
(Эта идея вдохновлена расширением Ruby andand.)
(На самом деле это вдохновлено языком Groovy, но большинство людей этого не знают;-)
Обновление: я думаю, что и Maybe(), и Eval {} являются хорошими решениями. Это не рубин, поэтому я не могу ожидать, что все методы / функции будут прочитаны слева направо, так что, возможно, может помочь. И тогда, конечно, Eval действительно Perl способ сделать это.
4 ответа
Я думаю, что только что написал это. Я только что загрузил его в CPAN, вы можете найти его здесь.
Я полагаю, ваш второй пример должен быть лучше:
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()
функционировать глобально, так что это, вероятно, будет намного медленнее, чем мой метод.
Вы можете использовать Perl's 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
с других языков; действительно, если вы используете модуль ошибок из CPAN, вы можете даже записать его try
, Стоит также отметить, что блочная форма eval (которую я демонстрировал выше) не сопровождается снижением производительности и компилируется вместе с остальным кодом. Струнная форма eval
(который я не показал) - совершенно другой зверь, и его следует использовать с осторожностью, если вообще.
eval
технически считается оператором в Perl, и, следовательно, является одним из немногих мест, где вы увидите точку с запятой в конце блока. Это легко забыть, если вы не используете eval
регулярно.
Павел
Что-то вроде (не проверено):
use Object::Generic::False;
sub UNIVERSAL::andand { $_[0] || Object::Generic::False->false }
UNIVERSAL автоматически является подклассом всех других классов, так что это обеспечивает andand для всех объектов. (Очевидно, что создание методов в UNIVERSAL может привести к конфликтам или неожиданным действиям на расстоянии, поэтому их не следует использовать небрежно.) Если объект, для которого вызывается метод andand, имеет значение true, вернуть его; в противном случае возвращает универсальный ложный объект, который возвращает себя для любого вызова метода, используемого для него.