Оператор Switch с возвратами-корректность кода


допустим, у меня есть код в C с примерно такой структурой:

switch (something)
{
    case 0:
      return "blah";
      break;

    case 1:
    case 4:
      return "foo";
      break;

    case 2:
    case 3:
      return "bar";
      break;

    default:
      return "foobar";
      break;
}

теперь очевидно, что "break" s не нужны для правильной работы кода, но это похоже на плохую практику, если я не помещаю их туда для меня.

что вы думаете? Это нормально, чтобы удалить их? Или вы бы сохранили их для повышения "правильности"?

17 67

17 ответов:

удалите инструкции break. Они не нужны, и, возможно, некоторые компиляторы будут выдавать предупреждения "недостижимый код".

Я бы выбрал совершенно другую тактику. Не возвращайтесь в середине метода / функции. Вместо этого просто поместите возвращаемое значение в локальную переменную и отправьте его в конце.

лично я считаю, что следующее будет более читаемым:

String result = "";

switch (something) {
case 0:
  result = "blah";
  break;
case 1:
  result = "foo";
  break;
}

return result;

лично я бы удалил возвраты и сохранил перерывы. Я бы использовал оператор switch для присвоения значения переменной. Затем вернуть эту переменную после оператора switch.

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

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

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

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

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

Я бы их удалил. В моей книге такой мертвый код следует считать ошибками, потому что он заставляет вас делать двойной дубль и спрашивать себя: "как бы я когда-нибудь выполнил эту строку?"

обычно я пишу код без них. ИМО, мертвый код, как правило, указывает на небрежность и/или отсутствие понимания.

конечно, я бы также рассмотрел что-то вроде:

char const *rets[] = {"blah", "foo", "bar"};

return rets[something];

Edit: даже с отредактированным сообщением эта общая идея может работать нормально:

char const *rets[] = { "blah", "foo", "bar", "bar", "foo"};

if ((unsigned)something < 5)
    return rets[something]
return "foobar";

в какой-то момент, особенно если входные значения разрежены (например, 1, 100, 1000 и 10000), вам нужен разреженный массив. Вы можете реализовать это как дерево или карту достаточно хорошо (хотя, конечно, переключатель все еще работает в этом случае).

Я бы сказал, удалить их и определить по умолчанию: ветвь.

не лучше ли иметь массив с

arr[0] = "blah"
arr[1] = "foo"
arr[2] = "bar"

и return arr[something];?

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

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

что вы думаете? Это нормально, чтобы удалить их? Или вы бы сохранили их для повышения "правильности"?

это нормально, чтобы удалить их. Используя return и ровно сценарий break Не следует использовать.

интересные. Консенсус из большинства этих ответов, похоже, заключается в том, что избыточный break заявление ненужную. С другой стороны, я читаю break оператор в коммутаторе как "закрытие" дела. case блоки, которые не заканчиваются break Как правило, выскакивают на меня, как потенциальные падения, хотя ошибки.

я знаю, что это не так, когда есть return вместо break, но именно так мои глаза "читают" блоки корпуса в коммутаторе, поэтому я лично предпочел бы, чтобы каждый case быть в паре с break. Но многие компиляторы жалуются на break после a return будучи лишним / недостижимым, и, по-видимому, я, кажется, в меньшинстве в любом случае.

так что избавьтесь от break после a return.

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

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

также я всегда предпочитал не смешивать перерывы и возвраты в операторе switch, а придерживаться одного из них.

Я лично склонен терять breaks. Возможно, одним из источников этой привычки является программирование оконных процедур для приложений Windows:

LRESULT WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SIZE:
            return sizeHandler (...);
        case WM_DESTROY:
            return destroyHandler (...);
        ...
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Я лично считаю этот подход намного проще, лаконичнее и гибче, чем объявление возвращаемой переменной, установленной каждым обработчиком, а затем возвращающей ее в конце. Учитывая такой подход, то breaks являются избыточными и поэтому должны идти - они не служат никакой полезной цели (синтаксически или визуально IMO) и только раздувают код.

Я думаю *перерыв * s существуют для определенной цели. Это идеология программирования в живых. Если мы просто "запрограммируем" наш код без логической согласованности, возможно, он будет читаем для вас сейчас, но попробуйте завтра. Попробуйте объяснить это своему боссу. Попробуйте запустить его на Windows 3030.

Bleah, идея очень проста:


Switch ( Algorithm )
{

 case 1:
 {
   Call_911;
   Jump;
 }**break**;
 case 2:
 {
   Call Samantha_28;
   Forget;
 }**break**;
 case 3:
 {
   Call it_a_day;
 }**break**;

Return thinkAboutIt?1:return 0;

void Samantha_28(int oBed)
{
   LONG way_from_right;
   SHORT Forget_is_my_job;
   LONG JMP_is_for_assembly;
   LONG assembly_I_work_for_cops;

   BOOL allOfTheAbove;

   int Elligence_says_anyways_thinkAboutIt_**break**_if_we_code_like_this_we_d_be_monkeys;

}
// Sometimes Programming is supposed to convey the meaning and the essence of the task at hand. It is // there to serve a purpose and to keep it alive. While you are not looking, your program is doing  // its thing. Do you trust it?
// This is how you can...
// ----------
// **Break**; Please, take a **Break**;

/* просто незначительный вопрос, хотя. Сколько кофе вы выпили, читая выше? И. Т. разрывы система иногда */

код выхода в одной точке. Это обеспечивает лучшую читаемость кода. Добавление операторов return (несколько выходов )между ними затруднит отладку.

Если у вас есть тип кода" lookup", вы можете упаковать предложение switch-case в методе самостоятельно.

У меня есть несколько из них в системе "хобби", которую я разрабатываю для удовольствия:

private int basePerCapitaIncomeRaw(int tl) {
    switch (tl) {
        case 0:     return 7500;
        case 1:     return 7800;
        case 2:     return 8100;
        case 3:     return 8400;
        case 4:     return 9600;
        case 5:     return 13000;
        case 6:     return 19000;
        case 7:     return 25000;
        case 8:     return 31000;
        case 9:     return 43000;
        case 10:    return 67000;
        case 11:    return 97000;
        default:    return 130000;
    }
}

(Ага. Вот и булькает космос...)

Я согласен с другими, что вы должны в большинстве случаев не более одного вернуться в способ, и я признаю, что это может быть лучше реализован как массив или что-то еще. Я только что нашел switch-case-return, чтобы быть довольно легко сопоставить таблицу поиска с корреляцией 1-1 между входом и выходом, как и выше (ролевые игры полны их, я уверен, что они существуют и в других "предприятиях"): D

С другой стороны, если предложение case более сложное или что-то происходит после оператора switch, я бы не рекомендовал использовать return в нем, а скорее установить переменную в коммутаторе, завершить ее разрывом и вернуть значение переменной в конце.

(на ... третье? рука... вы всегда можете рефакторинг перейти в свой собственный метод... Я сомневаюсь, что это повлияет на производительность, и меня не удивит, если современные компиляторы даже смогут распознать его как что-то, что может быть встроено...)