Заявление о выпуске Fallout... можно ли это разрешить?
До тех пор, пока я помню, я избегал использования инструкции switch switch. На самом деле, я не могу вспомнить, как он когда-либо входил в мое сознание как возможный способ сделать что-то, потому что он был пробурен в голову на ранней стадии, что это не что иное, как ошибка в инструкции switch. Тем не менее, сегодня я столкнулся с некоторым кодом, который использует его по дизайну, который заставил меня сразу же подумать о том, что все в сообществе думают о прохождении инструкции switch.
Является ли это тем, что язык программирования должен явно не разрешать (например, С#, хотя он предоставляет обходное решение), или это особенность любого языка, достаточно мощного для того, чтобы уйти в руки программиста?
Edit:
Я не был достаточно специфичен для того, что я имел в виду под падением. Я использую этот тип много:
switch(m_loadAnimSubCt){
case 0:
case 1:
// Do something
break;
case 2:
case 3:
case 4:
// Do something
break;
}
Однако меня беспокоит что-то вроде этого.
switch(m_loadAnimSubCt){
case 0:
case 1:
// Do something but fall through to the other cases
// after doing it.
case 2:
case 3:
case 4:
// Do something else.
break;
}
Таким образом, когда случай равен 0, 1, он будет делать все в инструкции switch. Я видел это по дизайну, и я просто не знаю, согласен ли я, что инструкции switch должны использоваться таким образом. Я думаю, что первый пример кода очень полезен и безопасен. Второй кажется опасным.
Ответы
Ответ 1
Это может зависеть от того, что вы считаете провалом. Я в порядке с такими вещами:
switch (value)
{
case 0:
result = ZERO_DIGIT;
break;
case 1:
case 3:
case 5:
case 7:
case 9:
result = ODD_DIGIT;
break;
case 2:
case 4:
case 6:
case 8:
result = EVEN_DIGIT;
break;
}
Но если у вас есть ярлык для случая, за которым следует код, который попадает на другой ярлык, я бы очень часто считал это зло. Возможно, переключение общего кода на функцию и вызов из обоих мест были бы лучшей идеей.
И обратите внимание, что я использую С++ FAQ определение "evil"
Ответ 2
Это обоюдоострый меч. Иногда очень полезно, часто опасно.
Когда это хорошо? Когда вы хотите, чтобы все 10 дел обрабатывались одинаково...
switch (c) {
case 1:
case 2:
... do some of the work ...
/* FALLTHROUGH */
case 17:
... do something ...
break;
case 5:
case 43:
... do something else ...
break;
}
Единственное правило, которое мне нравится, состоит в том, что если вы когда-либо делаете что-то необычное, когда вы исключаете перерыв, вам нужен четкий комментарий /* FALLTHROUGH */, чтобы указать, что это было вашим намерением.
Ответ 3
Патч действительно удобная вещь, в зависимости от того, что вы делаете. Рассмотрите этот опрятный и понятный способ организации вариантов:
switch ($someoption) {
case 'a':
case 'b':
case 'c':
// do something
break;
case 'd':
case 'e':
// do something else
break;
}
Представьте, что вы делаете это с if/else. Это будет беспорядок.
Ответ 4
Слышали ли вы о устройстве Duff? Это отличный пример использования переходного паттерна.
Это функция, которую можно использовать, и ее можно злоупотреблять, как почти все языковые функции.
Ответ 5
Это может быть очень полезно несколько раз, но, как правило, отсутствие провала - это желаемое поведение. Пауза должна быть разрешена, но не подразумевается.
Пример, чтобы обновить старые версии некоторых данных:
switch (version) {
case 1:
// update some stuff
case 2:
// update more stuff
case 3:
// update even more stuff
case 4:
// and so on
}
Ответ 6
Мне бы понравился другой синтаксис для резервных копий в переключателях, что-то вроде errr..
switch(myParam)
{
case 0 or 1 or 2:
// do something;
break;
case 3 or 4:
// do something else;
break;
}
Примечание. Это можно было бы сделать с перечислениями, если вы объявите все случаи на вашем перечислении с использованием флажков правильно? Не звучит так плохо, дела могут (должны?) Очень хорошо быть частью вашего перечисления уже.
Может быть, это был бы хороший случай (не каламбур) для свободного общения с использованием методов расширения? Что-то вроде, errr...
int value = 10;
value.Switch()
.Case(() => { /* do something; */ }, new {0, 1, 2})
.Case(() => { /* do something else */ } new {3, 4})
.Default(() => { /* do the default case; */ });
Хотя это, вероятно, еще менее читаемо: P
Ответ 7
Как и с любым: если использовать с осторожностью, это может быть элегантный инструмент.
Однако, я думаю, что недостатки более чем оправдывают НЕ использовать его и, наконец, больше не разрешают (С#). Среди проблем:
- легко "забыть" разрыв
- это не всегда очевидно для поддерживающих код, ЧТО пропущенный перерыв был преднамеренным
хорошее использование провала перехода/случая:
switch (x)
{
case 1:
case 2:
case 3:
do something
break;
}
BAAAAAD использует прохождение перехода/случая:
switch (x)
{
case 1:
some code
case 2:
some more code
case 3:
even more code
break;
}
Это можно переписать с использованием if/else конструкций без потери вообще на мой взгляд.
Мое последнее слово: держитесь подальше от пропущенных ярлыков case, как в примере BAD, если вы не поддерживаете устаревший код, где этот стиль используется и хорошо понятен.
Ответ 8
Мощный и опасный. Самая большая проблема с провалом заключается в том, что он не явный. Например, если вы сталкиваетесь с часто отредактированным кодом, в котором есть переключатель с провалами, откуда вы знаете, что это преднамеренное, а не ошибка?
В любом месте, где я его использую, я уверен, что он правильно прокомментировал:
switch($var) {
case 'first':
// fall-through
case 'second':
i++;
break;
}
Ответ 9
Мне не нравятся мои инструкции switch
, которые слишком подвержены ошибкам и трудно читаются. Единственным исключением является то, что несколько операторов case
выполняют одно и то же.
Если существует некоторый общий код, который нужно использовать несколькими ветвями оператора switch, я извлекаю его в отдельную общую функцию, которая может быть вызвана в любой ветки.
Ответ 10
Использование fall-through, как в вашем первом примере, очевидно, хорошо, я бы не считал это реальным провалом.
Второй пример опасен и (если не прокомментирован широко) неочевидно. Я преподаю своим ученикам не использовать такие конструкции, ЕСЛИ они считают целесообразным посвятить ему блок комментариев, который описывает, что это преднамеренное прохождение и почему это решение лучше, чем альтернативы. Это препятствует неаккуратурному использованию, но все же делает его допустимым в тех случаях, когда оно используется для преимущества.
Это более или менее эквивалентно тому, что мы делали в космических проектах, когда кто-то хотел нарушить стандарт кодирования: им нужно было подать заявку на диспансер (и меня вызвали, чтобы сообщить о решении).
Ответ 11
мысль о падении должна использоваться только тогда, когда она используется в качестве таблицы перехода в блок кода. Если какая-либо часть кода с безусловным перерывом перед другими случаями, все группы случаев должны заканчиваться таким образом. Все остальное - "зло".
Ответ 12
В некоторых случаях использование провалов - это акт лени со стороны программиста - они могут использовать серию || например, но вместо этого используйте серию случаев "все-все".
Как я уже сказал, я нашел их особенно полезными, когда я знаю, что в конечном итоге мне понадобятся параметры в любом случае (например, в ответе на меню), но еще не реализованы все варианты. Аналогично, если вы делаете провал как для "a", так и "A", я считаю его более чистым использовать переходный переход, чем оператор составной if.
Вероятно, это вопрос стиля и того, как думают программисты, но я вообще не люблю удалять компоненты языка во имя "безопасности", поэтому я склоняюсь к C и его вариантам/потомкам больше, чем, скажем, Java. Мне нравится быть в состоянии обезьяны вокруг с указателями и т.п., Даже когда у меня нет "причины".