Заявление о переключении - Switch statement

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

Операторы switch работают примерно так же, как если оператор, используемый в языках программирования, таких как C /C ++, C #, Visual Basic .NET, Ява и существует на самом высоком уровне императивное программирование языки, такие как Паскаль, Ада, C /C ++, C #, Visual Basic .NET, Ява, и во многих других языках, используя такие ключевые слова в качестве выключатель, дело, Выбрать или же осмотреть.

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

Оператор переключения в C
выключатель (возраст) {  дело 1:  printf("Ты один".);            перемена;  дело 2:  printf(«Вам двое».);            перемена;  дело 3:  printf(«Тебе три».);  дело 4:  printf(«Тебе три или четыре».);  перемена;  дефолт: printf("Ты не 1,2,3 или 4!");}

История

В своем тексте 1952 г. Введение в метаматематику, Стивен Клини формально доказано, что функция CASE (функция IF-THEN-ELSE является ее простейшей формой) является примитивная рекурсивная функция, где он определяет понятие определение по делам следующим образом:

"#F. Определенная таким образом функция φ
φ (х1 , ... , Иксп ) =
  • φ1(Икс1 , ... , Иксп ) если Q1(Икс1 , ... , Иксп ),
  • . . . . . . . . . . . .
  • φм(Икс1 , ... , Иксп ) если Qм(Икс1 , ... , Иксп ),
  • φм + 1(Икс1 , ... , Иксп ) иначе,
где Q1 , ..., Qм являются взаимоисключающими предикатами (или φ (x1 , ... , Иксп) должен иметь значение, указанное в первом применимом пункте) является примитивно рекурсивным в φ1, ..., φм + 1, Q1, ..., Qм + 1.[1]

Клини обеспечивает доказательство этого в терминах булевых рекурсивных функций «знак» sg () и «не знак» ~ sg () (Kleene 1952: 222-223); первый возвращает 1, если его вход положительный, и -1, если его вход отрицательный.

Булос-Берджесс-Джеффри делает дополнительное наблюдение, что «определение по случаям» должно быть как взаимоисключающим, так и исчерпывающим в совокупности. Они также предлагают доказательство примитивной рекурсивности этой функции (Boolos-Burgess-Jeffrey 2002: 74-75).

IF-THEN-ELSE является основой Формализм маккарти: его использование заменяет как примитивную рекурсию, так и мю-оператор.

Типичный синтаксис

В большинстве языков программисты пишут оператор switch во многих отдельных строках, используя одно или два ключевых слова. Типичный синтаксис включает:

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

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

Как правило, также допускается необязательный регистр по умолчанию, указанный в дефолт, иначе, или же еще ключевое слово. Это выполняется, когда ни один из других случаев не соответствует контрольному выражению. В некоторых языках, таких как C, если ни один регистр не соответствует, и дефолт опущено выключатель заявление просто выходит. В других, таких как PL / I, возникает ошибка.

Семантика

Семантически существует две основные формы операторов switch.

Первая форма - это структурированные переключатели, как в Паскале, где берется ровно одна ветвь, а варианты рассматриваются как отдельные исключительные блоки. Это функционирует как обобщенный if – then – else условный, здесь с любым количеством ветвей, а не только с двумя.

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

Провалиться

Во многих языках выполняется только соответствующий блок, а затем выполнение продолжается в конце оператора switch. К ним относятся Паскаль семейство (Object Pascal, Modula, Oberon, Ada и др.), а также PL / I, современные формы Фортран и БАЗОВЫЙ диалекты, на которые повлиял Паскаль, большинство функциональных языков и многие другие. Чтобы разрешить нескольким значениям выполнять один и тот же код (и избежать необходимости повторяющийся код ), Языки типа Pascal допускают любое количество значений для каждого случая, заданного в виде списка, разделенного запятыми, в виде диапазона или в виде комбинации.

Языки, производные от языка C, и в более общем плане те, на которые повлиял Fortran вычисленный GOTO, вместо этого функция откатывается, когда управление перемещается к соответствующему случаю, а затем выполнение продолжается ("проваливается") до операторов, связанных с следующий регистр в исходном тексте. Это также позволяет нескольким значениям соответствовать одной и той же точке без какого-либо специального синтаксиса: они просто перечислены с пустыми телами. Ценности могут быть специальный кондиционированный с кодом в корпусе корпуса. На практике провал обычно предотвращается с помощью перемена ключевое слово в конце соответствующего тела, которое завершает выполнение блока переключателя, но это может вызвать ошибки из-за непреднамеренного падения, если программист забывает вставить перемена утверждение. Это видят многие[2] как языковая бородавка, и от нее предостерегают в некоторых инструментах для удаления ворса. Синтаксически варианты интерпретируются как метки, а не блоки, а операторы switch и break явно изменяют поток управления. Некоторые языки, на которые повлиял C, например JavaScript, сохраните провал по умолчанию, в то время как другие удаляют провал или разрешают его только в особых обстоятельствах. Известные вариации этого в семействе C включают C #, в котором все блоки должны заканчиваться перемена или же возвращаться если блок не пуст (т. е. падение используется как способ указать несколько значений).

В некоторых случаях языки обеспечивают необязательный откат. Например, Perl не проваливается по умолчанию, но случай может явно сделать это с помощью Продолжить ключевое слово. Это предотвращает непреднамеренное падение, но позволяет при желании. Точно так же bash по умолчанию не проваливается, когда заканчивается ;; но в более поздних версиях можно использовать; &.

Примером оператора switch, который полагается на провал, является Устройство Даффа.

Компиляция

Оптимизация компиляторов Такие как GCC или же Лязг может скомпилировать оператор switch в любой разделительный стол или бинарный поиск через значения в корпусах.[3]Таблица переходов позволяет оператору switch определять с помощью небольшого постоянного числа инструкций, какую ветвь выполнять без необходимости просматривать список сравнений, в то время как двоичный поиск требует только логарифмического числа сравнений, измеряемого числом наблюдений в оператор переключения.

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

Преимущества и недостатки

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

  • Легче отлаживать (например, установка точек останова в коде по сравнению с таблицей вызовов, если отладчик не имеет возможности условной точки останова)
  • Человеку легче читать
  • Легче понять и, следовательно, проще поддерживать
  • Фиксированная глубина: последовательность операторов «if else if» может привести к глубокой вложенности, что затрудняет компиляцию (особенно в автоматически сгенерированном коде)
  • Легче проверить, обрабатываются ли все значения. Компиляторы могут выдавать предупреждение, если некоторые значения перечисления не обрабатываются.

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

Что касается граф потока управления, оператор switch состоит из двух узлов (входа и выхода) плюс одно ребро между ними для каждой опции. Напротив, последовательность операторов «if ... else if ... else if» имеет дополнительный узел для каждого случая, кроме первого и последнего, вместе с соответствующим ребром. Таким образом, получившийся граф потока управления для последовательностей «if» имеет намного больше узлов и почти вдвое больше ребер, при этом они не добавляют никакой полезной информации. Однако простые ветки в операторах if по отдельности концептуально проще, чем сложные ветвления оператора switch. С точки зрения цикломатическая сложность, оба эти варианта увеличивают его на k−1, если задано k случаи.

Альтернативные варианты использования

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

Например, в PHP, константа может использоваться в качестве «переменной» для проверки, и будет выполнен первый оператор case, который оценивает эту константу:

выключатель (истинный) {    дело ($ x == 'Привет'):        фу();        перемена;    дело ($ z == "привет"): перемена;}выключатель (5) {    дело $ x: перемена;    дело $ y: перемена;}

Эта функция также полезна для проверки нескольких переменных по одному значению, а не одной переменной по нескольким значениям. COBOL также поддерживает эту форму (и другие формы) в ОЦЕНИВАТЬ утверждение. PL / I имеет альтернативную форму ВЫБРАТЬ оператор, в котором контрольное выражение полностью опущено, а первое КОГДА что оценивается как истинный выполняется.

В Рубин, из-за обработки === равенство, оператор можно использовать для проверки класса переменной:

дело Входкогда Множество тогда ставит 'input - это массив!'когда Хеш тогда ставит 'ввод - это хэш!'конец

Ruby также возвращает значение, которое может быть присвоено переменной, и на самом деле не требует дело иметь какие-либо параметры (действуя как иначе если утверждение):

кошачья еда =  дело  когда Кот.возраст <= 1    младший  когда Кот.возраст > 10    старший  еще    нормальный  конец

Оператор переключения в язык ассемблера:

выключатель:  cmp ах, 00ч  je а  cmp ах, 01ч  je б  jmp Swtend   ; Здесь нет совпадений или кода "по умолчанию"а:  толкать ах  mov аль, 'а'  mov ах, 0Eh  mov бх, 00ч  int 10ч  поп ах  jmp Swtend   ; Эквивалентно "перерыв"б:  толкать ах  mov аль, 'b'  mov ах, 0Eh  mov бх, 00ч  int 10ч  поп ах  jmp Swtend   ; Эквивалентно "перерыв"  ...swtend:

Обработка исключений

Ряд языков реализуют форму оператора switch в Обработка исключений, где при возникновении исключения в блоке выбирается отдельная ветвь в зависимости от исключения. В некоторых случаях также присутствует ветвь по умолчанию, если исключение не возникает. Ранний пример - Модула-3, которые используют ПЫТАТЬСЯ...КРОМЕ синтаксис, где каждый КРОМЕ определяет случай. Это также находится в Delphi, Scala, и Visual Basic.NET.

Альтернативы

Некоторые альтернативы операторам переключения могут быть:

  • Серия если еще условные которые проверяют целевое значение по одному за раз. Поведение провала может быть достигнуто с помощью последовательности если условные выражения без еще пункт.
  • А Справочная таблица, который содержит в качестве ключей дело значения и, как значения, часть под дело утверждение.
(На некоторых языках в качестве значений в таблице подстановки разрешены только фактические типы данных. На других языках также можно назначить функции в качестве значений таблицы поиска, приобретая ту же гибкость, что и реальная выключатель утверждение. Видеть Контрольный стол статью для более подробной информации).
Lua не поддерживает операторы case / switch: http://lua-users.org/wiki/SwitchStatement . Этот метод поиска - один из способов реализовать выключатель операторы на языке Lua, в котором нет встроенных выключатель.[4]
В некоторых случаях справочные таблицы более эффективны, чем неоптимизированный выключатель операторы, поскольку многие языки могут оптимизировать поиск в таблицах, тогда как операторы switch не оптимизируются, если диапазон значений небольшой с небольшими пробелами. Неоптимизированный, неоптимизированныйбинарный поиск поиск, однако, почти наверняка будет медленнее, чем неоптимизированный переключатель или эквивалентное несколько если еще заявления.[нужна цитата ]
  • А таблица управления (который может быть реализован как простая таблица поиска) также может быть настроен для размещения нескольких условий на нескольких входах, если это необходимо, и обычно демонстрирует большую «визуальную компактность», чем эквивалентный переключатель (который может занимать много операторов).
  • Сопоставление с образцом, который используется для реализации функциональности переключателя во многих функциональный языков.

Смотрите также

Рекомендации

  1. ^ «Определение по падежам», Kleene 1952: 229.
  2. ^ ван дер Линден, Питер (1994). Экспертное программирование на C: секреты Deep C, п. 38. Прентис-Холл, Иглвуд-Клифс. ISBN  0131774298.
  3. ^ Влад Лазаренко. От оператора переключения к машинному коду
  4. ^ Оператор переключения в Lua

дальнейшее чтение

  • Стивен Клини, 1952 г. (10-е переиздание 1991 г.), Введение в метаматематику, Издательство North-Holland Publishing Company, Амстердам, Нидерланды, ISBN  0-7204-2103-9
  • Джордж Булос, Джон Берджесс, и Ричард Джеффри, 2002, Вычислимость и логика: четвертое издание, Издательство Кембриджского университета, Кембридж, Великобритания, ISBN  0-521-00758-5 мягкая обложка. см. стр. 74-75.