Какие существуют опрятные варианты использования для данных/когда?
Perl 5.10 ввел правильную конструкцию коммутатора с given/when
и он кажется мощным инструментом.
Однако в настоящее время perldoc perlsyn
не хватает хороших примеров.
В одном случае, когда я нашел его полезным, он использовал его с операторами проверки файлов:
given (-d "foo/bar/") {
when (1) { ... } # defined is wrong as -d returns '' on a file.
default { ... }
}
или, альтернативно:
given ("foo/bar/") {
when (-d) { ... }
default { ... }
}
Для меня, особенно первая версия выглядит лучше, чем конструкция if-else или использование тернарного оператора, когда в зависимости от результата теста мне нужно выполнять действия в обоих случаях.
Это заставило меня задуматься, хотя, что еще выглядит аккуратно, за исключением простого случая возврата назад к умному сопоставлению и избежания дополнительных структур if-elsif-elsif -...- else?
У меня есть предчувствие, которое дает/когда позволяет быть умным, не теряя ясности, но у меня нет хороших примеров.
Одна вещь, которая меня удивила, заключается в том, что вы можете также вложить конструкцию:
given ($filename) {
when (-e) {
when (-f) {
when (-z) { say "Empty file" }
default { say "Nonempty file" }
}
when (-d) {
when (-o) { say "Directory owned by me"}
default { say "Directory owned by someone else" }
}
default { say "Special" }
}
default { say "No such file or directory" } }
Ответы
Ответ 1
В недавнем ответе на вопрос Zaid Стратегии обработки файла с несколькими фиксированными форматами, я закончил с бедным человеком yacc, чей основной цикл искал массив регулярных выражений для первого совпадения:
while (<>) {
given($_) {
when (@{[ map $pattern{$_}, @expect ]}) {}
default {
die "$0: line $.: expected " . join("|" => @expect) . "; got\n$_";
}
}
}
В другом вопросе David B хотел совместить с несколькими регулярными выражениями, а мой ответ использует интеллектуальное сопоставление для неявной петли над регулярными выражениями:
#! /usr/bin/perl
use warnings;
use strict;
use feature 'switch';
my @patterns = (
qr/foo/,
qr/bar/,
qr/baz/,
);
for (qw/ blurfl bar quux foo baz /) {
print "$_: ";
given ($_) {
when (@patterns) {
print "hit!\n";
}
default {
print "miss.\n";
}
}
}
Ответ 2
Не знаю, является ли нижеследующее опрятное использование или просто кончиком шляпы для лингвистической линии Perl:)
# things todo (or should have done!) at this time of the day:
given (TheTime->of_day) {
when ('morning') {
breakfast();
make_packed_lunch() if $_->is_work_day;
}
lunch() when 'afternoon';
when ('evening') {
goto_pub() if $_->is_friday;
dinner();
}
default { say "Should be sleeping if its " . $_->{dt}->ymd }
}
И если вы видите $_
имеет "это", то это работает особенно хорошо (IMHO).
Вышеупомянутые работы перегружают оператор smart match, на который given/when
полагается. Вот как класс TheTime
мог быть написан для того, чтобы мой пример работал:
{
package TheTime;
use DateTime;
use overload '~~' => '_check_hour', fallback => 1;
our %day_time = (
morning => [0..11],
afternoon => [12..17],
evening => [18..23],
);
sub of_day {
my $class = shift;
bless {
dt => DateTime->now,
}, $class;
}
sub is_work_day { shift->{dt}->day_of_week ~~ [1..5] }
sub is_friday { shift->{dt}->day_of_week == 5 }
sub _check_hour {
my ($self, $greeting) = @_;
$self->{dt}->hour ~~ $day_time{$greeting};
}
}
/I3az/
PS. Также см. Это сообщение в блоге, которое я сделал недавно: заданный/когда - инструкция Perl switch