Должен ли я использовать Perl условно?: оператор как оператор switch/case или вместо if elsif?
Perl имеет оператор conditional, который является тем же C условный оператор.
Чтобы обновить, условный оператор в C и Perl:
(test) ? (if test was true) : (if test was false)
и если используется с lvalue, вы можете назначить и протестировать одним действием:
my $x= $n==0 ? "n is 0" : "n is not 0";
Я читал блог Игоря Островского на Яркий способ выразить многопозиционные предложения, если на языках C-языков, и понял, что это действительно "опрятный путь" в Perl.
Например: (изменить: использовать более читаемую форму Jonathan Leffler...)
# ternary conditional form of if / elsif construct:
my $s=
$n == 0 ? "$n ain't squawt"
: $n == 1 ? "$n is not a lot"
: $n < 100 ? "$n is more than 1..."
: $n < 1000 ? "$n is in triple digits"
: "Wow! $n is thousands!" ; #default
Что читает LOT проще, чем то, что многие будут писать в Perl:
(редактирование: используется cjm более элегантная форма my $t=do{ if };
в ответе rafi)
# Perl form, not using Switch or given / when
my $t = do {
if ($n == 0) { "$n ain't squawt" }
elsif ($n == 1) { "$n is not a lot" }
elsif ($n < 100) { "$n is more than 1..." }
elsif ($n < 1000) { "$n is in triple digits" }
else { "Wow! $n is thousands!" }
};
Есть ли какие-то ошибки или недостатки? Почему бы мне не написать расширенную условную форму таким образом, а не использовать if(something) { this } elsif(something) { that }
?
Условный оператор имеет правую ассоциативность и низкий приоритет. Итак:
a ? b : c ? d : e ? f : g
интерпретируется как:
a ? b : (c ? d : (e ? f : g))
Возможно, вам понадобится скобка, если в ваших тестах использовался один из немногих операторов с более низким приоритетом, чем ?:
. Думаю, вы могли бы также разместить блоки в форме с фигурными скобками.
Я знаю об устаревших конструкциях use Switch
или о Perl 5.10 given/when
, и я не ищу предложения использовать их.
Это мои вопросы:
-
Вы видели этот синтаксис, используемый в Perl? ** У меня нет, и он не находится в perlop
или perlsyn
как альтернатива коммутатору.
-
Существуют ли потенциальные проблемы синтаксиса или "gotchas" с использованием условного/тернарного оператора таким образом?
-
Мнение: это более читаемо/понятно для вас? Согласуется ли это с Idiomatic Perl?
-------- Редактировать -
Я принял ответ Джонатана Леффлера, потому что он указал мне на Perl Best Practices. Соответствующий раздел - 6.17 на табличных тернарах. Это позволило мне продолжить изучение использования. (Если вы используете Google Perl Tabular Ternaries, вы можете увидеть другие комментарии.)
Конвей два примера:
my $salute;
if ($name eq $EMPTY_STR) {
$salute = 'Dear Customer';
}
elsif ($name =~ m/\A ((?:Sir|Dame) \s+ \S+)/xms) {
$salute = "Dear $1";
}
elsif ($name =~ m/([^\n]*), \s+ Ph[.]?D \z/xms) {
$sa1ute = "Dear Dr $1";
}
else {
$salute = "Dear $name";
}
VS:
# Name format... # Salutation...
my $salute = $name eq $EMPTY_STR ? 'Dear Customer'
: $name =~ m/ \A((?:Sir|Dame) \s+ \S+) /xms ? "Dear $1"
: $name =~ m/ (.*), \s+ Ph[.]?D \z /xms ? "Dear Dr $1"
: "Dear $name"
;
Мои выводы:
-
Пример Conway ?:
более читабельный и более простой для меня, чем форма if/elsif
, но я мог видеть, как форма может быть трудно понять.
-
Если у вас есть Perl 5.13.1, используйте my $t=do { given { when } };
как назначение как rafi. Я думаю, given/when
- лучшая идиома сейчас, если табличный трехмерный формат не подходит для вашего конкретного случая.
-
Если у вас есть Perl 5.10+, используйте given/when
вообще вместо Switch
или если вам нужен какой-то тип типа case.
-
Старые Perl, это прекрасная форма для простых альтернатив или как альтернатива описанию case. Это лучше, чем использовать Switch
.
-
Соотношение справа налево означает, что форма оценивается снизу вверх. Помните, что при использовании...
Ответы
Ответ 1
Макет, показанный для условного оператора, трудно читать.
Это больше похоже на то, что я помню Perl Best Practices, рекомендую:
my $s = $n == 0 ? "$n ain't squawt"
: $n == 1 ? "$n is not a lot"
: $n < 100 ? "$n is more than 1..."
: $n < 1000 ? "$n is in triple digits"
: "Wow! $n is thousands!"; # default...
И бывают случаи, когда лучше использовать более компактную нотацию с обозначением if
тоже:
if ($n == 0) { $t = "$n ain't squawt"; }
elsif ($n == 1) { $t = "$n is not a lot"; }
elsif ($n < 100) { $t = "$n is more than 1..."; }
elsif ($n < 1000) { $t = "$n is in triple digits"; }
else { $t = "Wow! $n is thousands!" ; }
Оба этих переформатирования подчеркивают сходство различных разделов кода, что облегчает их чтение и понимание.
Ответ 2
Я видел эту идиому, используемую в perl. Так как тернарный оператор ? :
есть, ну.. оператор, он задокументирован в perlop
, а не perlsyn
.
В моих глазах это своего рода идиоматический Perl, но главная цель этого в Perl, по-видимому, не позволяет избежать правильного выражения switch
, не пиши огромные if/else
-каскады. Однако это было зафиксировано несколько лет назад в perl 5.10.0. В эти дни я не вижу многих причин не писать выше, как это, что представляется гораздо читабельнее, чем (ab), используя тройной:
given ($n) {
when (0) { $t = "$_ ain't squawt" }
when (1) { $t = "$_ is not a lot" }
when ($_ < 100) { $t = "$_ is more than 1..." }
when ($_ < 1000) { $t = "$_ is in triple digits" }
default { $t = "Wow! $_ is thousands!" }
}
или, начиная с perl 5.13.1, даже как:
my $t = do {
given ($n) {
when (0) { "$_ ain't squawt" }
when (1) { "$_ is not a lot" }
when ($_ < 100) { "$_ is more than 1..." }
when ($_ < 1000) { "$_ is in triple digits" }
default { "Wow! $_ is thousands!" }
}
};
Другим вариантом может быть что-то вроде этого, которое работает на всех версиях perl:
my @cases = (
[sub { $_ == 0 }, sub { "$_ ain't squawt" }],
[sub { $_ == 1 }, sub { "$_ is not a lot" }],
[sub { $_ < 100 }, sub { "$_ is more than 1..." }],
[sub { $_ < 1000 }, sub { "$_ is in triple digits" }],
[sub { 1 }, sub { "Wow! $_ is thousands!" }],
);
for my $case (@cases) {
local $_ = $n;
next unless $case->[0]->();
$t = $case->[1]->();
last;
}
Хотя это позволяет избежать использования огромных if/elsif/else
-каскадов и не нуждается в функциях последних perls, это, вероятно, не стоит усилий для этого простого примера. Тем не менее, я очень хорошо понимаю, что такой подход полезен при множестве условий и с ограничением необходимости поддержки старых perls.
(Также обратите внимание, что ваш исходный пример не обрабатывает $n меньше нуля или вообще не является числом.)
Примечание cjm. Вы также можете сделать это во всех версиях Perl 5:
my $t = do {
if ($n == 0) { "$n ain't squawt" }
elsif ($n == 1) { "$n is not a lot" }
elsif ($n < 100) { "$n is more than 1..." }
elsif ($n < 1000) { "$n is in triple digits" }
else { "Wow! $n is thousands!" }
};
Ответ 3
Я видел скопированные условные условия совсем немного, иногда использовал его и всегда ненавидел. Это удобно, но некрасиво, если вы не переходите в крайности, чтобы отформатировать его и упростить межстраничные выражения.
Их не так сложно понять, как только вы столкнетесь с ними пару раз и осознаете, что это идиома. Тем не менее, проще понять правильную инструкцию switch. Там также меньше шансов убрать толстую кишку и втиснуть все в затруднительное положение.
Ответ 4
И еще один способ!
my $t = sub {
return "$n ain't squawt" if $n == 0;
return "$n is not a lot" if $n == 1;
return "$n is more than 1..." if $n < 100;
return "$n is in triple digits" if $n < 1000;
return "Wow! $n is thousands!";
}->();
Я затрагиваю это в нескольких сообщениях в блоге, которые я сделал:
/I3az/