Подтвердить что ты не робот

Почему Switch/Case, а не If/Else If?

Этот вопрос в основном указывается на C/С++, но я думаю, что другие языки также актуальны.

Я не могу понять, почему используется параметр switch/case вместо if/else if. Мне очень нравится использование goto's и приводит к тому же виду беспорядочного кода, в то время как те же результаты могут быть достигнуты с if/else, если более организованным образом.

Тем не менее, я вижу эти блоки довольно часто. Общепринятое место для их нахождения находится рядом с контуром сообщений (WndProc...), тогда как они относятся к местам, когда они поднимают самый тяжелый хаос: переменные разделяются по всему блоку, даже если они не являются подходящими (и не могут быть инициализируется внутри него). Дополнительное внимание нужно уделять не прекращению перерыва, и так далее...

Лично я не использую их, и мне интересно, что я чего-то не хватает?

Являются ли они более эффективными, чем if/else? Продолжают ли они традиции?

4b9b3361

Ответ 1

Подводя итоги моей первоначальной публикации и комментариев - существует несколько преимуществ инструкции switch над выражением if/else:

  • Чистый код. Код с несколькими цепями if/else if ... выглядит грязным и его трудно поддерживать - switch дает более чистую структуру.

  • Производительность

    . Для плотных case значений компилятор генерирует таблицу перехода, для разреженного бинарного поиска или серии if/else, поэтому в худшем случае switch работает так же быстро, как if/else, но обычно быстрее. Хотя некоторые компиляторы также могут оптимизировать if/else.

  • Тестовый заказ не имеет значения. Чтобы ускорить серию тестов if/else, сначала нужно поставить более вероятные случаи. Программисту switch/case не нужно об этом думать.

  • Значение по умолчанию может быть в любом месте. При значении if/else значение по умолчанию должно быть в самом конце - после последнего else. В switch - default может быть где угодно, где программист считает его более подходящим.

  • Общий код. Если вам нужно выполнить общий код для нескольких случаев, вы можете опустить break, и выполнение будет "проваливаться" - чего вы не можете достичь с помощью if/else. (Существует хорошая практика разместить специальный комментарий /* FALLTHROUGH */ для таких случаев - lint распознает его и не жалуется, без этого комментария он жалуется, поскольку обходиться с ошибкой забыть break).

Спасибо всем комментаторам.

Ответ 2

Ну, одна из причин - ясность....

если у вас есть переключатель /case, то выражение не может измениться.... то есть.

switch (foo[bar][baz]) {
case 'a':
    ...
    break;
case 'b': 
    ...
    break;
}

тогда как с if/else, если вы пишете по ошибке (или намерению):

if (foo[bar][baz] == 'a') {
    ....
}
else if (foo[bar][baz+1] == 'b') {
    ....
}

люди, читающие ваш код, задаются вопросом: "Были ли выражения foo одинаковыми" или "почему они разные"?

Ответ 3

помните, что case/select обеспечивает дополнительную гибкость:

  • условие оценивается один раз
  • достаточно гибкая, чтобы создавать такие вещи, как устройство Duff
  • прохождение (aka case без разрыва)

а также выполняется намного быстрее (через таблицу прыжка/поиска) * исторически

Ответ 4

Также помните, что инструкции switch позволяют продолжить управление потоком, что позволяет вам хорошо комбинировать условия, позволяя вам добавлять дополнительный код для определенных условий, например, в следующий фрагмент кода:

switch (dayOfWeek)
{
    case MONDAY:
        garfieldUnhappy = true;
    case TUESDAY:
    case WEDNESDAY:
    case THURSDAY:
    case FRIDAY:
       weekDay = true;
       break;
    case SATURDAY:
       weekendJustStarted = true;
    case SUNDAY:
       weekendDay = true;
       break;
}

Использование здесь if/else утверждений не будет таким приятным.

if (dayOfWeek == MONDAY)
{
    garfieldUnhappy = true;
}
if (dayOfWeek == SATURDAY)
{
    weekendJustStarted = true;
}
if (dayOfWeek == MONDAY || dayOfWeek == TUESDAY || dayOfWeek == WEDNESDAY
    || dayOfWeek == THURSDAY || dayOfWeek == FRIDAY)
{
    weekDay = true;
}
else if (dayOfWeek == SATURDAY || dayOfWeek == SUNDAY)
{
    weekendDay = true;
}

Ответ 5

Если есть много случаев, оператор switch кажется более чистым.

Также хорошо, когда у вас есть несколько значений, для которых вы хотите иметь такое же поведение - просто использование нескольких "случайных" операторов, которые попадают в одну реализацию, намного легче читать, чем if (this || that || someotherthing | |...)

Ответ 6

Это может также зависеть от вашего языка. Например, некоторые языки переключаются только с числовыми типами, поэтому он сохраняет вас при наборе текста, когда вы работаете с перечисляемым значением, числовыми константами... и т.д.

If (day == DAYOFWEEK_MONDAY) {
    //...
}
else if (day == DAYOFWEEK_TUESDAY) {
    //...
}
//etc...

Или немного легче читать...

switch (day) {
    case DAYOFWEEK_MONDAY :
        //...
    case DAYOFWEEK_TUESDAY :
        //...
    //etc...
}

Ответ 7

Коммутатор/случай обычно оптимизирован более эффективно, чем if/else if/else, но иногда (в зависимости от языка и компилятора) переводится в простые операторы if/else if/else.

Я лично считаю, что операторы switch делают код более читаемым, чем кучу операторов if; при условии, что вы выполните несколько простых правил. Правила, которые вы, вероятно, должны соблюдать даже для ситуаций if/else if/else, но это снова мое мнение.

Эти правила:

  • Никогда, никогда, не более одной строки на вашем блоке коммутатора. Вызовите метод или функцию и выполните свою работу там.
  • Всегда проверяйте прохождение патча/случая.
  • Исключение пузырьков.

Ответ 8

Clarity. Как я сказал здесь, ключ, который else if проблематичен, это

частота, с которой ELSE IF используется гораздо более ограниченным образом чем разрешено синтаксисом. Это кувалдой гибкости, разрешая полностью несвязанные условия, подлежащие испытанию. Но это обычно используется для сматывания мух CASE, сравнивая одно и то же выражение с альтернативными значениями...

Это уменьшает читаемость код. Поскольку структура позволяет вселенная условной сложности, читателю необходимо сохранить больше возможности при анализе ELSE IF, чем при разборе CASE.

Ответ 9

На самом деле оператор switch означает, что вы работаете над чем-то более или менее перечислением, которое дает вам мгновенное представление о том, что происходит.

Тем не менее, переключатель на перечислении на любом языке OO, вероятно, может быть лучше закодирован - и ряд значений if/else по одному и тому же значению стиля "enum" будет по крайней мере столь же плохим и даже хуже при передаче смысла.

Ответ 10

обращая внимание на то, что все внутри коммутатора имеет эквивалентную область видимости, вы всегда можете отбросить свою логику вашего дела в другой блок {}, например.

switch( thing ) {
    case ONETHING: {
        int x; // local to the case!
        ...
        }
        break;
    case ANOTHERTHING: {
        int x; // a different x than the other one
        }
        break;
}

.. теперь я не говорю это красиво. Просто поместите это там как нечто, что возможно, если вам абсолютно необходимо изолировать что-то в одном случае от другого.

еще одна мысль о проблеме области - кажется хорошей практикой только поставить один переключатель внутри функции, а не многое другое. В этих условиях переменная область не столько беспокоит, что вы обычно имеете дело только с одним случаем выполнения при любом вызове функции.

ok, последняя мысль о коммутаторах: если функция содержит более двух коммутаторов, возможно, потребуется время для реорганизации вашего кода. Если функция содержит вложенные ключи, это, вероятно, ключ к переосмыслению вашей конструкции бит =)

Ответ 11

Случай переключения в основном используется для выбора в программировании. Это не связано с условным выражением как:

Если ваша программа требует только выбора, то почему вы используете блок if/else и увеличиваете усилия по программированию, а также уменьшаете скорость выполнения программы.

Ответ 12

Довольно уверены, что они скомпилируются с теми же вещами, что и if/else if, но я считаю, что switch/case легче читать, если их больше 2 или 3 else s.

Ответ 13

Операторы switch могут быть оптимизированы для скорости, но могут занимать больше памяти, если значения case распределены по большим числам значений.

if/else обычно медленны, так как каждое значение необходимо проверить.

Ответ 14

Smalltalker может отклонить оба ключа и if-then-else и может написать что-то вроде: -

shortToLongDaysMap := Dictionary new.

shortToLongDaysMap
at: 'Mon'     put:  'Monday';
at: 'Tue'     put:  'Tuesday';
at: 'Wed'     put:  'Wednesday'
etc etc.

longForm := shortToLongDaysMap at: shortForm ifAbsent: [shortForm]

Это тривиальный пример, но я надеюсь, вы можете увидеть, как этот метод масштабируется для большого числа случаев.

Обратите внимание, что второй аргумент at:IfAbsent: похож на предложение по умолчанию для оператора case.

Ответ 15

Основная причина этого - удобство и удобочитаемость. Его легко сделать код более читабельным и поддерживаемым с помощью оператора Switch/case, а затем if/else. Поскольку у вас много, если /else, тогда код становится настолько грязным, как гнездо, и его очень сложно поддерживать.

И некоторые, как время выполнения является другой причиной.