В одном из моих первых обзоров кода (некоторое время назад) мне сказали, что хорошей практикой является включение предложения по умолчанию во все операторы switch. Я недавно вспомнил этот совет, но не могу вспомнить, каково было оправдание. Это звучит довольно странно для меня сейчас.
Есть ли разумная причина всегда включать оператор по умолчанию?
Этот язык зависит? Я не помню, какой язык я использовал в то время - может быть, это относится к некоторым языкам, а не к другим?
default
switch-statement
tttppp
источник
источник
Ответы:
Переключатель дел должен почти всегда иметь
default
дело.Причины использовать
default
1. «поймать» неожиданное значение
2. Для обработки действий «по умолчанию», где случаи для особого поведения.
Вы видите это много в программах, управляемых меню и сценариях оболочки bash. Вы также можете увидеть это, когда переменная объявляется вне регистра, но не инициализируется, и каждый случай инициализирует ее чем-то другим. Здесь по умолчанию нужно также инициализировать его, чтобы код строки, обращающийся к переменной, не вызывал ошибку.
3. Чтобы показать, что кто-то читает ваш код, вы рассмотрели этот случай.
Это был упрощенный пример, но суть в том, что тот, кто читает код, не должен удивляться, почему
variable
не может быть что-то, кроме 1 или 2.Единственный случай, о котором я могу подумать, чтобы НЕ использовать,
default
это когда коммутатор проверяет что-то, где его довольно очевидная любая альтернатива может быть счастливо проигнорирована.источник
enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;
делает допустимыйMyEnum
экземпляр, который не равенFOO
илиBAR
. Если любая из этих проблем приведет к ошибке в вашем проекте, случай по умолчанию поможет вам найти ошибку очень быстро, часто без необходимости в отладчике!Нет.
Что если нет действия по умолчанию, контекст имеет значение. Что делать, если вы хотите действовать только на нескольких ценностях?
Возьмите пример чтения нажатий клавиш для игры
Добавление:
Это просто трата времени и увеличивает сложность кода без причины.
источник
// do nothing
комментарием проясняет, что это «хорошо», если не все случаи покрыты, в отличие от других операторов switch, где это было бы «не хорошо».НЕ иметь стандартный регистр может быть полезным в некоторых ситуациях.
Если ваши варианты переключения являются перечисляемыми значениями, не имея регистра по умолчанию, вы можете получить предупреждение компилятора, если пропустите какие-либо случаи. Таким образом, если новые значения enum будут добавлены в будущем, и вы забудете добавить регистры для этих значений в коммутаторе, вы сможете узнать о проблеме во время компиляции. Вы все равно должны убедиться, что код выполняет соответствующие действия для необработанных значений, в случае, если недопустимое значение было приведено к типу enum. Так что это может лучше всего подойти для простых случаев, когда вы можете вернуться в enum case, а не break.
источник
Я бы всегда использовал предложение по умолчанию, независимо от того, на каком языке вы работаете.
Вещи могут и действительно пойти не так, как надо. Ценности будут не такими, как вы ожидаете, и так далее.
Отсутствие необходимости включать предложение по умолчанию означает, что вы уверены, что знаете набор возможных значений. Если вы считаете, что знаете набор возможных значений, то, если значение выходит за пределы этого набора возможных значений, вы хотите, чтобы об этом сообщили - это, безусловно, ошибка.
Вот почему вы всегда должны использовать предложение по умолчанию и выдавать ошибку, например, в Java:
Нет причин включать больше информации, чем просто «недостижимая» строка; если это действительно произойдет, вам все равно придется посмотреть на источник, значения переменных и т. д., и трассировка стека исключений будет включать этот номер строки, поэтому не нужно тратить свое время на запись большего количества текста в сообщение об исключении.
источник
throw new RuntimeException("myVar invalid " + myVar);
поскольку это может дать вам достаточно информации, чтобы выяснить и исправить ошибку без необходимости использовать отладчик и проверять переменные, что может быть трудно, если это редко встречающаяся проблема, которую сложно воспроизвести.default:
. Но чаще всего этого не происходит, каждый оставляет значение по умолчанию, потому что думает, чтоmyVar
никогда не может иметь никакого значения, кроме перечисленных; однако я не могу сосчитать, сколько раз я был удивлен в реальной жизни, когда переменная имела значение, отличное от значений, которые она «могла бы» иметь. В этих случаях я был благодарен за исключение, заставляющее меня увидеть это сразу, а не вызывать какую-то другую ошибку позже (более трудную для отладки) или неправильный ответ (может быть пропущен при тестировании).AssertionError
вместоRuntimeException
, так как эта ситуация очень похожа на утверждение о том, чтоmyVar
это одно из обрабатываемых значений. Также меньше вероятность того, что кто-то поймает и проглотит ошибку.В моей компании мы пишем программное обеспечение для рынка авионики и обороны, и мы всегда включаем оператор по умолчанию, потому что ВСЕ случаи в операторе switch должны явно обрабатываться (даже если это просто комментарий, говорящий «ничего не делать»). Мы не можем позволить программному обеспечению просто вести себя неправильно или просто зависать от неожиданных (или даже тех, которые мы считаем невозможными) значений.
Можно обсудить, что случай по умолчанию не всегда необходим, но, всегда требуя его, он легко проверяется нашими анализаторами кода.
источник
Должен ли оператор switch всегда включать предложение по умолчанию? Нет. Обычно включать в себя по умолчанию.
Включение предложения по умолчанию имеет смысл только в том случае, если для этого нужно что-то сделать, например утвердить условие ошибки или обеспечить поведение по умолчанию. Включение одного «только потому, что» является культовым программированием и не дает никакой ценности. Это эквивалент «переключателя», когда все операторы «если» должны включать «еще».
Вот тривиальный пример того, где это не имеет смысла:
Это эквивалент:
источник
default:
в этих случаях кодифицирует ваши предположения. Например, это нормально, когдаsgn==0
печататьinteger
(ни положительный, ни отрицательный), или это ошибка? Для меня, читающего этот код, сложно сказать. Я бы предположил, что вы не хотите писатьzero
в этом случаеinteger
, и что программист сделал предположение, чтоsgn
может быть только -1 или +1. Если бы это было так, наличие этого параметраdefault:
позволило бы программисту отлавливать допущенную ошибку заранее и изменять код.Насколько я вижу, ответ «по умолчанию» является необязательным, говорить, что переключатель должен всегда содержать значение по умолчанию, все равно, что говорить, что каждое if-elseif должно содержать «else». Если есть логика, которая должна быть сделана по умолчанию, тогда должен присутствовать оператор 'default', но в противном случае код мог бы продолжать выполняться, ничего не делая.
источник
Оборонное программирование обычно имеет предложение по умолчанию, когда оно на самом деле не нужно. Это обычно приводит к слишком сложному коду из-за слишком большого количества кода обработки ошибок. Этот код обработки и обнаружения ошибок ухудшает читабельность кода, усложняет обслуживание и в конечном итоге приводит к большему количеству ошибок, чем решает.
Поэтому я считаю, что если по умолчанию не будет достигнуто - вам не нужно его добавлять.
Обратите внимание, что «не должно быть достигнуто» означает, что если оно достигнуто, то это ошибка в программном обеспечении - вам нужно проверить значения, которые могут содержать нежелательные значения из-за ввода пользователя и т. Д.
источник
Я бы сказал, что это зависит от языка, но в C, если вы включаете тип enum и обрабатываете все возможные значения, вам, вероятно, лучше НЕ включать регистр по умолчанию. Таким образом, если позже вы добавите дополнительный тег enum и забудете добавить его в коммутатор, компетентный компилятор выдаст вам предупреждение о пропущенном регистре.
источник
gcc -Wall
(своего рода наименьший общий знаменатель компетентных компиляторов) выдает предупреждения о необработанных перечислениях в выражениях switch.Если вы знаете, что оператор switch будет иметь только строго определенный набор меток или значений, просто сделайте это для охвата баз, таким образом вы всегда получите правильный результат. Просто установите значение по умолчанию над меткой, которая будет программно / логически быть лучшим обработчиком для других значений.
источник
default
? Или это позволяет использовать какой-то особый синтаксис, который позволял вам его опускать?По крайней мере, это не обязательно в Java. Согласно JLS, он говорит, что может присутствовать как минимум один случай по умолчанию. Это означает, что ни один случай по умолчанию не приемлем. Время от времени также зависит от контекста, который вы используете оператор switch. Например, в Java следующий блок переключателей не требует регистра по умолчанию
Но в следующем методе, который ожидает вернуть строку, случай по умолчанию пригодится, чтобы избежать ошибок компиляции
хотя вы можете избежать ошибки компиляции для вышеприведенного метода, не используя регистр по умолчанию, просто добавив оператор return в конце, но предоставив регистр по умолчанию, он станет более читабельным.
источник
Так говорят некоторые (устаревшие) руководства, такие как MISRA C :
Этот совет устарел, потому что он не основан на соответствующих в настоящее время критериях. Явное упущение - то, что сказал Харлан Кэслер:
Если оставить регистр по умолчанию, компилятор может опционально предупредить или завершить работу при обнаружении необработанного регистра. Статическая верификация в конце концов лучше, чем любая динамическая проверка, и, следовательно, не является достойной жертвой, когда вам также нужна динамическая проверка.
Как также показал Харлан, функциональный эквивалент случая по умолчанию может быть воссоздан после переключения. Что тривиально, когда каждый случай является ранним возвращением.
Типичная потребность в динамической проверке - это обработка ввода в широком смысле. Если значение приходит из-за пределов контроля программы, ему нельзя доверять.
Это также тот случай, когда Мисра придерживается позиции крайне оборонительного программирования, поэтому, пока недопустимое значение является физически представимым, его нужно проверять, независимо от того, является ли программа корректной. Что имеет смысл, если программное обеспечение должно быть максимально надежным при наличии аппаратных ошибок. Но, как сказал Офир Йоктан, большинство программного обеспечения лучше не «обрабатывать» ошибки. Последняя практика иногда называется оскорбительным программированием .
источник
У вас должно быть значение по умолчанию для перехвата ожидаемых значений.
Однако я не согласен с Адрианом Смитом, что ваше сообщение об ошибке по умолчанию должно быть совершенно бессмысленным. Может быть необработанный случай, который вы не предвидели (что-то вроде этого), что ваш пользователь в конечном итоге увидит, и сообщение типа «недоступный» совершенно бессмысленно и никому не поможет в этой ситуации.
Например, сколько раз у вас был совершенно бессмысленный BSOD? Или фатальное исключение @ 0x352FBB3C32342?
источник
Если значение переключателя ( switch (переменная )) не может достичь значения по умолчанию, тогда значение по умолчанию вообще не требуется. Даже если мы сохраняем регистр по умолчанию, он вообще не выполняется. Это мертвый код.
источник
Это необязательное кодирование «соглашение». В зависимости от использования, является ли это необходимо или нет. Я лично считаю, что если вам это не нужно, его не должно быть. Зачем включать что-то, что не будет использоваться или достигнуто пользователем?
Если возможности регистра ограничены (т. Е. Булево), то предложение по умолчанию является избыточным !
источник
Если в
switch
операторе нет случая по умолчанию , поведение может быть непредсказуемым, если этот случай возникает в какой-то момент времени, что не было предсказуемо на этапе разработки. Хорошей практикой является включениеdefault
дела.Такая практика может привести к ошибке, такой как разыменование NULL , утечка памяти, а также к другим типам серьезных ошибок .
Например, мы предполагаем, что каждое условие инициализирует указатель. Но если
default
предполагается возникновение кейса и если мы не инициализируем в этом случае, то есть все шансы получить исключение с нулевым указателем. Следовательно, предлагается использовать операторdefault
case, хотя он может быть тривиальным.источник
Случай по умолчанию может не понадобиться в ключе, используемом enum. когда switch содержит все значения, регистр по умолчанию никогда не будет выполнен. Так что в этом случае это не обязательно.
источник
Зависит от того, как работает переключатель на определенном языке, однако на большинстве языков, когда ни один регистр не соответствует, выполнение проваливается через оператор switch без предупреждения. Представьте, что вы ожидали некоторый набор значений и обрабатывали их в switch, однако вы получаете другое значение на входе. Ничего не происходит, и вы не знаете, ничего не случилось. Если вы поймали дело по умолчанию, вы бы знали, что что-то не так.
источник
Я не согласен с наиболее проголосовавшим ответом Ванварила выше.
Любой код добавляет сложности. Также тесты и документация должны быть сделаны для этого. Так что всегда хорошо, если вы можете программировать, используя меньше кода. Мое мнение таково, что я использую предложение по умолчанию для неисчерпывающих операторов переключения, в то время как я не использую предложение по умолчанию для исчерпывающих операторов переключения. Чтобы быть уверенным, что я все сделал правильно, я использую инструмент статического анализа кода. Итак, давайте углубимся в детали:
Неисчерпывающие операторы switch: они всегда должны иметь значение по умолчанию. Как следует из названия, это утверждения, которые не охватывают все возможные значения. Это также может быть невозможно, например, оператор switch для целочисленного значения или для String. Здесь я хотел бы использовать пример Vanwaril (Следует отметить, что я думаю, что он использовал этот пример, чтобы сделать неправильное предложение. Я использую его здесь, чтобы заявить обратное -> Использовать выражение по умолчанию):
Игрок может нажать любую другую клавишу. Тогда мы ничего не могли сделать (это можно показать в коде, просто добавив комментарий к случаю по умолчанию), или это должно, например, напечатать что-нибудь на экране. Этот случай актуален, как это может случиться.
Исчерпывающие операторы переключения: Эти операторы переключения охватывают все возможные значения, например, оператор переключения для перечисления типов систем оценок. При разработке кода в первый раз легко охватить все значения. Однако, поскольку мы люди, есть небольшой шанс забыть о некоторых. Кроме того, если вы добавите значение enum позже, так что все операторы switch должны быть адаптированы, чтобы сделать их исчерпывающими, снова откроется путь в ад ошибки. Простое решение - инструмент статического анализа кода. Инструмент должен проверить все операторы switch и проверить, являются ли они исчерпывающими или имеют ли они значение по умолчанию. Вот пример для исчерпывающего оператора switch. Сначала нам нужно перечисление:
Тогда нам нужна переменная этого перечисления, как
GradeSystemType type = ...
. Исчерпывающий оператор switch будет выглядеть следующим образом:Поэтому, если мы расширим
GradeSystemType
, например,System1To3
инструмент статического анализа кода должен обнаружить, что предложение по умолчанию отсутствует, а оператор switch не является исчерпывающим, поэтому мы сохраняем.Еще одна вещь. Если мы всегда используем
default
предложение, может случиться так, что инструмент статического анализа кода не способен обнаруживать исчерпывающие или не исчерпывающие операторы переключения, поскольку он всегда обнаруживаетdefault
предложение. Это очень плохо, так как мы не будем проинформированы, если мы расширим enum другим значением и забудем добавить его в один оператор switch.источник
Должны ли операторы switch всегда содержать предложение по умолчанию? Случаи переключений не могут существовать без случая по умолчанию, в случае переключателя значение
switch(x)
по умолчанию вызовет значение переключателя в этом случае x, если оно не совпадает с любыми другими значениями случая.источник
Я полагаю, что это довольно специфично для языка и для случая C ++ второстепенный момент для класса enum типа . Который кажется более безопасным, чем традиционное перечисление. НО
Если вы посмотрите на реализацию std :: byte, это выглядит примерно так:
Источник: https://en.cppreference.com/w/cpp/language/enum
А также учтите это:
Источник: https://en.cppreference.com/w/cpp/language/list_initialization
Это пример класса enum, представляющего значения, которые не определены перечислителем. По этой причине вы не можете полностью доверять перечислениям. В зависимости от приложения это может быть важно.
Однако мне действительно нравится то, что @Harlan Kassler сказал в своем посте, и я сам начну использовать эту стратегию в некоторых ситуациях.
Просто пример небезопасного класса enum:
источник