Заявление о выпуске 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. Мне нравится быть в состоянии обезьяны вокруг с указателями и т.п., Даже когда у меня нет "причины".