Зачем переключать / Case, а не If / Else If?
этот вопрос в основном указывал на C / C++, но я думаю, что другие языки также актуальны.
Я не могу понять, почему switch/case все еще используется вместо if/else if. Мне кажется, что это очень похоже на использование goto, и приводит к такому же беспорядочному коду, в то время как те же результаты могут быть получены с помощью if/else if в гораздо более организованном виде.
тем не менее, я вижу эти блоки вокруг довольно часто. Общее место для их поиска находится рядом с циклом сообщений (WndProc...), в то время как они являются одними из мест, когда они вызывают самый тяжелый хаос: переменные разделяются по всему блоку, даже если они не являются собственностью (и не могут быть инициализированы внутри него). Дополнительное внимание должно быть обращено на то, чтобы не уронить перерыв, и так далее...
лично я избегаю их использовать, и мне интересно, что я чего-то не хватает?
Они более эффективны, чем if/else?
Они продолжаются по традиции?
15 ответов:
Резюмируя мой первоначальный пост и комментарии-есть несколько преимуществ
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 */для таких случаев-Линт распознает его и не жалуется, без этого комментария он жалуется, так как это распространенная ошибка забытьbreak).спасибо всем комментаторам.
Ну, одна из причин заключается в ясности....
Если у вас есть переключатель/случае, то выражение не может измениться.... то есть
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 одинаковыми "или"почему они разные"?
пожалуйста, помните, что case / select обеспечивает дополнительную гибкость:
- состояние оценивается как
- является достаточно гибким, чтобы построить такие вещи, как устройство Даффа
- fallthrough (он же случай без перерыва)
а также он выполняется гораздо быстрее (через таблицу перехода / поиска) * исторически
также помните, что операторы 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; }
Если есть много случаев, оператор switch кажется чище.
также приятно, когда у вас есть несколько значений, для которых вы хотите одно и то же поведение - просто используя несколько операторов "case", которые попадают в одну реализацию, гораздо легче читать, чем if( this || that || someotherthing || ... )
Это также может зависеть от вашего языка-например, некоторые языки switch работает только с числовыми типами, поэтому он экономит вам некоторое количество ввода, когда вы работаете с перечисляемым значением, числовыми константами... так далее...
If (day == DAYOFWEEK_MONDAY) { //... } else if (day == DAYOFWEEK_TUESDAY) { //... } //etc...или немного легче читать...
switch (day) { case DAYOFWEEK_MONDAY : //... case DAYOFWEEK_TUESDAY : //... //etc... }
Switch/case обычно оптимизируется более эффективно, чем if/else if/else, но иногда (в зависимости от языка и компилятора) переводится на простые операторы if/else if / else.
Я лично думаю, что операторы switch делают код более читаемым, чем куча операторов if; при условии, что вы следуете нескольким простым правилам. Правила, которые вы, вероятно, должны соблюдать даже для ваших ситуаций if/else if/else, но это снова мое мнение.
те правила:
- никогда, никогда, не имейте больше чем одну линию на вашем блоке переключателя. Вызовите метод или функцию и сделайте свою работу там.
- всегда проверяйте на разрыв / случай падения.
- пузырь до исключения.
ясность. Как я уже сказал здесь, понятия
else ifпроблематичночастота, с которой еще если используется в гораздо более ограниченном виде чем позволяет синтаксис. Это кувалда гибкости, разрешений не имеют никакого отношения условия, подлежащие испытанию. Но это обычно используется для прихлопывания мух Случай, сравнивая одно и то же выражение с альтернативными значениями...
это снижает читаемость код. Поскольку структура позволяет Вселенная условной сложности, читатель должен держать больше возможности в виду при анализе Иначе если чем при разборе дела.
на самом деле оператор switch подразумевает, что вы работаете с чем-то, что является более или менее перечислением, которое дает вам мгновенную подсказку о том, что происходит.
тем не менее, переключатель на перечислении на любом языке OO, вероятно, может быть закодирован лучше-и серия if/else на том же значении стиля "enum" будет по крайней мере такой же плохой и еще хуже при передаче смысла.
решая проблему, что все внутри коммутатора имеет эквивалентную область, вы всегда можете бросить свою логику case в другой блок {}, например ..
switch( thing ) { case ONETHING: { int x; // local to the case! ... } break; case ANOTHERTHING: { int x; // a different x than the other one } break; }.. я не говорю, что это довольно. Просто положить его там, как что-то, что возможно если вы абсолютно должны изолировать что-то в одном случае от другого.
еще одна мысль о проблеме области-похоже, что хорошая практика заключается только в том, чтобы поместить один переключатель внутри функции, и больше ничего. В этих обстоятельствах переменная scope не так много беспокоит, так как таким образом вы обычно имеете дело только с одним случаем выполнения при любом вызове функции.
хорошо, последняя мысль о переключателях: если функция содержит более нескольких переключателей, вероятно, пришло время для рефакторинга вашего кода. Если функция содержит вложенные переключатели, это, вероятно, ключ к переосмыслению вашего дизайна немного =)
случае переключатель главным образом использован для того чтобы иметь выбор сделал в программировании .Это не связано с условным утверждением как:
Если ваша программа требует только выбора, то почему вы используете блок if/else и увеличиваете усилие программирования плюс уменьшаете скорость выполнения программы .
операторы Switch могут быть оптимизированы для скорости, но могут занимать больше памяти, если значения case распределены по большому количеству значений.
Если/else, как правило, медленно, так как каждое значение должно быть проверено.
Smalltalker может отклонить как switch, так и 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.
основной причиной этого является ремонтопригодность и читаемость. Его легко сделать код более читаемым и поддерживаемым с помощью оператора Switch/case, а затем if/else. Потому что у вас есть много if/else, тогда код становится настолько грязным, как гнездо, и его очень трудно поддерживать.
и некоторые, как время выполнения является еще одной причиной.
довольно уверен, что они компилируются к тем же вещам, что и
if/else if, но я найтиswitch/caseлегче читать, когда есть больше, чем 2 или 3elses.
Comments