Разбить случай по умолчанию в коммутаторе

88

Я немного озадачен тем, когда включаю или не включаю breakпосле последнего случая, часто default.

switch (type) {
    case 'product':

        // Do behavior

        break;
    default:

        // Do default behavior

        break; // Is it considered to be needed?
}

breakв моем понимании единственная цель - остановить выполнение кода через остальную часть регистра switch.

Тогда считается ли более логичным иметь breakпоследнее из-за непротиворечивости или пропустить его из-за breakотсутствия функционального использования вообще? И то и другое логично по-моему.

Это можно в определенной степени сравнить с окончанием .phpфайла ?>. Я никогда не заканчиваю в ?>основном из-за риска вывода пробелов, но можно утверждать, что было бы логично завершить файл.

Робин Кастлин
источник

Ответы:

144

breakтехнически не требуется после последней альтернативы (что, к вашему сведению, необязательно default: это совершенно законно, а иногда даже полезно ставить defaultветку на первое место); независимо от того, проваливается ли ваш код в конце switchоператора или breaksвыходит в конце его последней ветви, результат будет одинаковым.

Тем не менее, я бы по-прежнему заканчивал каждую ветку, включая последнюю, оператором returnили breakпо трем причинам:

  1. Refactorability. Если все ваши ветви заканчиваются на breakили return, вы можете изменить их порядок без изменения значения. Это снижает вероятность того, что при таком переупорядочении будет введена регрессия.
  2. Последовательность и наименьший сюрприз. Последовательность говорит, что ваши ветви должны заканчиваться последовательно, если они на самом деле не имеют другого значения. Принцип Наименьшего Сюрприза гласит, что похожие вещи должны выглядеть одинаково. Завершение последней ветви switchблока точно так же, как и предыдущие, выполняет обе функции, что облегчает чтение и понимание. Если вы не укажете явное break, последняя ветвь будет оптически отличаться (что особенно важно для быстрого сканирования), и, чтобы увидеть, что она на самом деле не отличается, читатель должен опуститься до мельчайшего уровня чтения отдельных операторов. ,
  3. Защищать себя. Если у вас есть привычка заканчивать все свои switchветви буквой a break, через некоторое время она станет автоматической, и вы с меньшей вероятностью случайно забудете об этом, где это имеет значение. Тренировка себя ожидать breakв конце каждой ветки также помогает обнаруживать пропущенные breakоператоры, что отлично подходит для отладки и устранения неполадок.
tdammers
источник
Спасибо за ваше понимание этого! Будет breakдлиться последний случай :)
Робин Кастлин
7
В C #, break(или другого заявлении потока управления , который выходит из case) является технически необходимо после последней альтернативы.
dan04
3
@ dan04: да, хорошая мысль. C # здесь исключение, и это, вероятно, потому, что разработчики языка знали о проблемах с switchошибками в существующих языках и хотели их предотвратить. Правила C # навязывают в значительной степени совпадение с рекомендациями из моего ответа.
tdammers
На каком языке вы говорите конкретно? C? C ++? C #? Ява? PHP?
svick
2
Хороший компилятор будет рассматривать финал breakкак NO-OP вместо генерации jmpследующей инструкции, правильно?
Натан Осман
11

Учитывая неоднозначность, которая существует вокруг использования switch-caseв большинстве языков, при его использовании я бы предложил всегда использовать breakвыражение, за исключением случаев, когда оно явно и по замыслу нежелательно .

Отчасти это происходит потому, что каждый caseвызов выглядит одинаково, что, на мой взгляд, улучшает читабельность. Но это также означает, что если кто-то (даже вы) решит вставить caseпосле последнего на более позднем этапе, ему не нужно заботиться о проверке предыдущего блока, что может помочь уменьшить количество ошибок при добавлении нового кода.


источник
7
Когда я хочу, чтобы один случай перешел к другому (а это не вырожденный случай case foo: case bar: ...), я помещаю явный комментарий в то, что я хочу, чтобы это произошло. Делает это намного яснее.
Donal Fellows
3
Да, как простой комментарий // no breakвместоbreak;
Pacerier
Или [[fallthrough]]атрибут в случае C ++.
Руслан
1

Там нет breakнеобходимости после последнего случая. Я использую слово « последний » (не по умолчанию ), потому что это не обязательно. Случай по умолчанию - последний случай.

switch(x)
{
case 1:
//do stuff
break;

default:
//do default work
break;

case 3:
//do stuff

}

И мы знаем, что break необходимо между двумя последовательными caseс. Иногда я использую if(a!=0)в своем коде для большей читабельности, когда другие ссылаются на мой код. Я могу выбрать для использования if(a), это было бы вопросом моего выбора

Суварна Паттайил
источник
5
Для меня это означало бы «всегда использовать разрыв», на всякий случай, если какой-нибудь программист добавит новый caseв конце вашего, switchне проверив, что он breakдействительно существует (это будет ошибка этого программиста, но все же лучше быть в безопасности - если по какой-либо причине, потому что вы могли бы быть этим программистом через 6
месяцев-
@ SJuan76 Да, я согласен, лучше, чем потом сожалеть, если вы хотите сохранить защиту от будущих ошибок, вы должны включить ее в конце.
Суварна Паттайил
1
Имея в виду этот аргумент, вы также можете утверждать, что всегда иметь , в конце массивов в случае вставки нового значения. Однако это нарушает некоторые коды и в целом выглядит ужасно :)
Робин Кастлин
1
@ Робин Ввод запятой отличается. Если его там нет и кто-то добавляет новое значение в массив, он получит ошибку компиляции. Однако не будет ошибки компиляции, если в предыдущем операторе case пропущен разрыв - так что это может быть пропущено и вызвать ошибки во время выполнения.
Кит Миллер
@RobinCastlin При условии, что язык позволил вам поставить ,. Incase, defaultбыл разработан, чтобы быть последним случаем. Может быть, язык посчитает breakпосле этого ошибку. Допущение breakбыло разрешено в качестве разграничения ТОЛЬКО между двумя случаями.
Суварна Паттайил