Відповідне використання операторів перемикання, що пропускаються


14

Коли доцільно використовувати випадок (класичний) вимикач перемикача? Чи рекомендується та заохочується таке використання чи його слід уникати будь-якою ціною?


Не всі мови дозволяють пропустити оператори перемикання.
Одід

@Змінено, відредаговано, додано "класичне" слово. Не всі мови дозволяють провалитися, проте я наполягаю, що це класично)
shabunc

3
Якщо ви говорите про пристрій Дафса , це одне.
Одід

6
@Oded: Це перше, про що думають більшість людей, але це навряд чи "доречно". Відповідно до цього , Дафф сам сказав: "Це безумовно є аргументом в дискусії про те, чи повинен перемикач пропускатися за замовчуванням, але я не впевнений, аргумент" за "чи" проти ".
BlueRaja - Danny Pflughoeft

Відповіді:


15

Ось приклад, де це було б корисно.

public Collection<LogItems> GetAllLogItems(Level level) {
    Collection<LogItems> result = new Collection<LogItems>();
    switch (level) {
        // Note: fall through here is INTENTIONAL
        case All:
        case Info:
             result.Add(GetItemsForLevel(Info));
        case Warning:
             result.Add(GetItemsForLevel(Warning));
        case Error:
             result.Add(GetItemsForLevel(Error));
        case Critical:
             result.Add(GetItemsForLevel(Critical));
        case None:
    }
    return result;
}

Думаю, подібні речі (де один випадок включає інший) є досить рідкісними, тому деякі новіші мови або не дозволяють перепадати, або потребують спеціального синтаксису.


13
Цей приклад, хоч і цікавий, не має необхідного // INTENTIONAL FALL THROUGH HEREкоментаря з усіма кришками .
Рассел Борогов,

Написати цей код із пропусканням так само просто, коли GetItemsForLevel(Info)виклик дзвінка GetItemsForLevel(Warning)тощо.
Калеб

@RussellBorogove: Абсолютно правильно.
конфігуратор

@Caleb: У цьому випадку так. Але що робити, якщо дзвінки були трохи складнішими? Він може трохи волохатися, тоді як провалитися - це здається простим. Слід зазначити, що я фактично не за те, щоб використовувати падіння - я просто кажу, що це може бути корисним у певних ситуаціях.
конфігуратор

Не найкращий приклад. Є впорядкування рівнів попередження. Визначаючи це впорядкування, цей спосіб зменшується до одного рядка елементів фільтрування коду, коли рівень елемента принаймні дорівнює бажаному рівню.
кевін клайн

8

Я використовую їх, коли певна функціональність повинна застосовуватися для більш ніж одного значення. Наприклад, скажіть, у вас був об’єкт із властивістю під назвою OperationCode. Якщо код дорівнює 1, 2, 3 або 4, потрібно запустити OperationX (). Якщо це 5 або 6, потрібно запустити OperationY (), а 7 - startOperationZ (). Чому у вас є 7 повних справ із функціональністю та перервами, коли ви можете використовувати пропускні дані?

Я думаю, що це цілком справедливо в певних ситуаціях, особливо якщо він уникає 100 тверджень інше. =)


4
Те, що ви описуєте, - це switchдекілька cases, прив'язаних до одного коду. Це інакше, ніж провал, коли виконання одного caseпродовжується в наступне через відсутність breakміж ними.
Blrfl

3
Це насправді не має значення, пропуск - це лише відсутність заяви про перерву, тому він "провалюється" до наступного випадку.
Ятрікс

Я б переписав сценарій у вашій відповіді, щоб це відобразити.
Blrfl

2
@Yatrix: Я не згоден. Набагато інше, щоб послідовні випадки виконували абсолютно той самий блок коду, ніж пропускати перерву. Одне є звичайним, інше - далеко від нього (ім'я) - і потенціал для неправильного читання та ненавмисного потоку управління набагато більший.
квентін-зірин

3
@qes так, це інакше, але вони обидва є прохідними. Він запитав, коли / якщо це буде доречно. Я наводив приклад, коли це станеться. Це не мав бути прикладом всеохоплюючого характеру. Залежно від мови, висловлювання перед провалом може не працювати. Я не думаю , що це буде з C # stackoverflow.com/questions/174155 / ...
Yatrix

8

Я використовував їх час від часу, я вважаю, що це завжди доречне використання, але лише тоді, коли вони включені у відповідний коментар.


7

Шафи, що пронизуються, прекрасно виглядають. Я часто виявляю, що перерахування використовується в багатьох місцях, і коли вам не потрібно розмежовувати деякі випадки, простіше використовувати логіку пропускання.

Наприклад (зверніть увагу на пояснювальні коментарі):

public boolean isAvailable(Server server, HealthStatus health) {
  switch(health) {
    // Equivalent positive cases
    case HEALTHY:
    case UNDER_LOAD:
      return true;

    // Equivalent negative cases
    case FAULT_REPORTED:
    case UNKNOWN:
    case CANNOT_COMMUNICATE:
      return false;

    // Unknown enumeration!
    default:
      LOG.warn("Unknown enumeration " + health);
      return false;
  }
}

Я вважаю такий вид використання цілком прийнятним.


Зауважте, що велика різниця між case X: case Y: doSomething()та case X: doSomething(); case Y: doAnotherThing(). У першому намір є досить явним, тоді як у другому провал може бути навмисним чи ні. На мій досвід, перший приклад ніколи не викликає попереджень у компіляторах / аналізаторах коду, тоді як другий. Особисто я б назвав лише другий приклад "провалитися" - але не впевнений у "офіційному" визначенні.
Йенс Банманн

6

Це залежить від:

  • ваші особисті переваги
  • стандарти кодування роботодавця
  • кількість пов'язаного з цим ризику

Дві основні проблеми, пов'язані з тим, щоб один випадок перейшов у інший, є:

  1. Це робить ваш код залежним від порядку заяв справи. Це не так, якщо ви ніколи не пропадаєте, і це додає ступеня складності, яка часто є небажаною.

  2. Не очевидно, що код для одного випадку включає код для одного або декількох наступних випадків.

Деякі місця прямо забороняють пробиватися. Якщо ви не працюєте в такому місці і якщо вам подобається практика, і якщо порушення коду, про який йде мова, не спричинить справжніх страждань, то це може бути не найгірше в світі. Якщо ви це зробите, не забудьте поруч поставити привертаючий увагу коментар, щоб попередити тих, хто прийде пізніше (включаючи майбутнього ви).


4

Ось швидкий (мабуть, неповний (без спеціального поводження з високосний рік)) приклад пропуску, який полегшує моє життя:

function get_julian_day (date) {
    int utc_date = date.getUTCDate();
    int utc_month = date.getUTCMonth();

    int julian_day = 0;

    switch (utc_month) {
        case 11: julian_day += 30;
        case 10: julian_day += 31;
        case 9:  julian_day += 30;
        case 8:  julian_day += 31;
        case 7:  julian_day += 31;
        case 6:  julian_day += 30;
        case 5:  julian_day += 31;
        case 4:  julian_day += 30;
        case 3:  julian_day += 31;
        case 2:  julian_day += 28;
        case 1:  julian_day += 31;
        default: break;
    }

    return julian_day + utc_date;
}

5
Незважаючи на те, що це дуже розумно, час, який ви заощадите від цього, буде значно перевищувати час, який потрібно іншим людям, щоб зрозуміти, що це робить. Крім того, ви можете досягти кращої продуктивності, видаливши прохідний аспект, тобто 31 + 28 + 31 завжди 90. Якщо ви збираєтесь це зробити, ви можете просто поставити підсумки у випадках, оскільки їх потрібно розглянути лише 11.
JimmyJames

Ви маєте рацію, мій приклад, безумовно, надуманий :) Я скажу, однак, простіше помітити приховану помилку, коли прописано кількість днів таким чином, а не попередньо обчислити всі сукупні дні для кожного випадку перемикача .
AaronDanielson

2
Я дозволю вам це, але бажано робити це в постійній декларації, наприклад, FEB_START = 31; MAR_START = FEB_START + 28; і т.д. не впевнений, що це за мова, але в багатьох випадках це було б обчислено під час компіляції. Більша проблема тут полягає в тому, що це трохи тупо. Не стільки, що це погана ідея, просто нетипова. Якщо не існує дійсно великої вигоди, загалом краще дотримуватися загальних ідіом.
JimmyJames

1
Відмінна альтернатива, використовуючи константи для початкових днів на цьому прикладі. У будь-якому разі, суть тут у тому, що сукупна сума є чудовим використанням для переходу на випадок комутації. Я погоджуюсь на 100% у використанні загальних ідіом, але характер цього питання вникає в більш езотеричні особливості, де загальні ідіоми важко знайти.
AaronDanielson

3

Якщо я відчуваю потребу переходити від однієї справи до іншої (рідко, правда,), я вважаю за краще бути дуже чітким і goto case , звичайно, маючи на увазі, що ваша мова це підтримує.

Оскільки падіння через таке явище нечасте, і дуже легко його не помітити під час читання коду, я вважаю, що доречно бути явним - і гото, навіть якщо це стосується справи, повинно виділятися, як болілий палець.

Це також допомагає уникнути помилок, які можуть виникнути, коли викладені випадки перепорядковані.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.