Оператор переключения
Эта статья требует дополнительных цитат для проверки . ( апрель 2013 г. ) |
В языках компьютерного программирования - оператор переключателя это тип механизма управления выбором, используемый для обеспечения значения переменной или выражения для изменения потока управления выполнением программы с помощью поиска и карты.
Операторы переключения функционируют несколько аналогично if
Заявление, используемое на языках программирования, таких как C / C ++ , C# , Visual Basic .net , Java и существует на самых высокоуровневых императивных языках программирования, таких как Pascal , ADA , C / C ++ , C# , [ 1 ] : 374–375 Visual Basic .net , Java , [ 2 ] : 157–167 и во многих других типах языка, используя такие ключевые слова , как switch
, case
, select
или inspect
.
Операторы коммутатора бывают двух основных вариантов: структурированный переключатель, как в Pascal, который занимает ровно одну ветвь, и неструктурированный коммутатор, как в C, который функционирует как тип Goto . Основные причины использования переключателя включают улучшение ясности, путем снижения повторяющегося кодирования и (если разрешение на эвристику ) также предлагает потенциал для более быстрого выполнения посредством более легкой оптимизации компилятора во многих случаях.
switch (age) {
case 1: printf("You're one."); break;
case 2: printf("You're two."); break;
case 3: printf("You're three.");
case 4: printf("You're three or four."); break;
default: printf("You're not 1, 2, 3 or 4!");
}
|
История
[ редактировать ]В своем тексту 1952 года введение в метаматематику Стивен Клейн формально доказал, что функция случая (функция if-then-else является ее простейшей формой) является примитивной рекурсивной функцией , где он определяет определение понятия «случаями» в следующем виде: следующим образом:
"#F. Функция φ определена таким образом
- φ (x 1 , ..., x n ) =
- φ 1 (x 1 , ..., x n ), если q 1 (x 1 , ..., x n ),
- . . . . . . . . . . . .
- φ m (x 1 , ..., x n ), если q m (x 1 , ..., x n ),
- φ m+1 (x 1 , ..., x n ) в противном случае,
где Q 1 , ..., Q M являются взаимоисключающими предикатами (или φ (x 1 , ..., x n ) должны иметь значение, указанное в первом предложении, которое применяется), является примитивным рекурсивным в φ 1 , ... , φ M+1 , Q 1 , ..., Q M+1 .
- Стивен Клин, [ 3 ]
Kleene предоставляет доказательство этого с точки зрения логических рекурсивных функций «sg-of» sg () и «не признака» ~ sg () (Kleene 1952: 222-223); Первый возвращает 1, если его вход является положительным и -1, если его вход отрицательный.
Boolos-Burgess-Jeffrey делает дополнительное наблюдение, что «определение по случаям» должно быть как взаимоисключающим, так и коллективным исчерпывающим . Они также предлагают доказательство примитивной рекурсивности этой функции (Boolos-Burgess-Jeffrey 2002: 74-75).
If-then-else является основой формализма McCarthy : его использование заменяет как примитивную рекурсию, так и MU-оператор .
Самые ранние компиляторы Fortran поддержали вычислимый оператор GOTO для многоподобного ветвления. Ранние компиляторы Algol поддерживали тип данных переключения, который содержит список «обозначенных выражений». Оператор GOTO может ссылаться на переменную коммутатора и, предоставляя индекс, ветвь в нужное место. С опытом было понято, что необходима более формальная многопользовательская конструкция с единственной точкой входа и выхода. Такие языки, как BCPL , Algol-W и Algol-68 , внедрили формы этой конструкции, которые выжили через современные языки.
Типичный синтаксис
[ редактировать ]На большинстве языков программисты пишут оператор переключателя во многих отдельных строках, используя одно или два ключевых слова. Типичный синтаксис включает в себя:
- первый
select
с последующим выражением, которое часто называют управляющим выражением или управляющей переменной операции переключателя - Последующие строки, определяющие фактические случаи (значения), с соответствующими последовательностями операторов для выполнения, когда происходит совпадение
- На языках с поведением в осеннее
break
Заявление обычно следуетcase
Заявление о прекращении указанного заявления. [Уэллс] - На некоторых языках, например, PL/I , управляющее выражение является необязательным; Если нет контрольного выражения, то каждая альтернатива начинается с
WHEN
Пункт, содержащий логическое выражение и совпадение, происходит для первого случая, для которого это выражение оценивается в True. Это использование аналогично структурам if/then/elseif/else на некоторых других языках, например, perl . - На некоторых языках, например, REXX , контрольное выражение не допускается, и каждая альтернатива начинается с
WHEN
Пункт, содержащий логическое выражение и совпадение, происходит для первого случая, для которого это выражение оценивается в True.
Каждая альтернатива начинается с конкретного значения или списка значений (см. Ниже), что управляющая переменная может соответствовать и которая приведет к тому, что элемент управления затронет соответствующую последовательность операторов. Значение (или список/диапазон значений) обычно отделяется от соответствующей последовательности операций толстой кишкой или со стрелкой для значения. На многих языках каждому случаю также должно предшествовать ключевое слово, такое как case
или when
.
Необязательный случай по умолчанию обычно также разрешен, указанный default
, otherwise
, или else
ключевое слово. Это выполняется, когда ни один из других случаев не соответствует управляющему выражению. На некоторых языках, таких как C, если ни один случай не совпадает и default
опускается switch
Заявление просто ничего не делает. В других, как PL/I, возникает ошибка.
Семантика
[ редактировать ]Семантически, существует две основные формы операторов переключения.
Первая форма - это структурированные переключатели, как в Паскале, где занимается ровно одна ветвь, а случаи рассматриваются как отдельные, исключительные блоки. if -then -else Это функционирует как обобщенное условие , здесь с каким -либо количеством ветвей, а не только двумя.
Вторая форма - это неструктурированные переключатели, как в C, где случаи рассматриваются как этикетки в одном блоке, а коммутатор функционирует как обобщенное Goto. Это различие называется лечением осеннего, которое разрабатывается ниже.
Осенний
[ редактировать ]Во многих языках выполняется только соответствующий блок, а затем выполнение продолжается в конце оператора Switch. К ним относятся семейство Паскаля (объект Pascal, Modula, Oberon, ADA и т. Д.), А также PL/I , современные формы FORTRAN и основные диалекты, на которые влияют Pascal, большинство функциональных языков и многие другие. Чтобы позволить нескольким значениям выполнять один и тот же код (и избегать необходимости дублировать код ), языки типа Паскаля позволяют любому количеству значений в случае, указанном в виде списка, разделенного запятыми, в виде диапазона или в качестве комбинации.
Языки, полученные из языка C, и, в целом, под влиянием вычисленного Goto Fortran , вместо этого функционируют падение, где управление перемещается в случай сопоставления, а затем выполнение продолжается («падает») к утверждениям, связанным со следующим случаем в исходном тексте Полем Это также позволяет нескольким значениям соответствовать одной и той же точке без какого -либо специального синтаксиса: они только что перечислены с пустыми телами. Значения могут быть специальными обусловленными с кодом в корпусе случая. На практике, осеннее обычно предотвращается break
Ключевое слово в конце соответствующего тела, которое выходит из выполнения блока коммутатора, но это может вызвать ошибки из -за непреднамеренного падения, если программист забудет вставить break
заявление. Таким образом, это видно многими [ 4 ] Как языковая бородавка и предупреждая в некоторых инструментах с ворсом. Синтаксически, случаи интерпретируются как метки, а не блоки, а операторы переключения и разрыва явно изменяют поток управления. Некоторые языки под влиянием C, такие как JavaScript , сохраняют по умолчанию падение, в то время как другие удаляют падение или разрешают его только в особых обстоятельствах. Примечательные вариации этого в семействе C включают C# , в котором все блоки должны быть прекращены с помощью break
или return
Если блок не пуст (то есть осеннее используется как способ указать несколько значений).
В некоторых случаях языки обеспечивают дополнительное падение. Например, Perl не пропадает по умолчанию, но случай может явно сделать это, используя continue
ключевое слово. Это предотвращает непреднамеренное падение, но позволяет ему при желании. Точно так же BASH по умолчанию не проваливаться при прекращении ;;
, но допускает падение [ 5 ] с ;&
или ;;&
вместо.
Примером оператора переключения, который полагается на осеннее устройство, является устройство Даффа .
Компиляция
[ редактировать ]Оптимизация компиляторов, таких как GCC или Clang, может составлять оператор переключателя в таблицу ветвей или двоичный поиск через значения в случаях. [ 6 ] Таблица филиала позволяет оператору переключения определять с небольшим, постоянным количеством инструкций, которые ветви должны выполнять без необходимости просмотреть список сравнений, в то время как двоичный поиск требует только логарифмического количества сравнений, измеряемого в количестве случаев в оператор переключения.
Обычно единственный метод выяснения того, произошла ли эта оптимизация, - это фактически рассмотрение результирующей сборки или выхода машинного кода , который был сгенерирован компилятором.
Преимущества и недостатки
[ редактировать ]В некоторых языках и средах программирования использование case
или switch
Заявление считается превосходящим эквивалентную серию IF ESE ESLE, если это если: это:
- Легче отладки (например, установление точек останова на коде и таблице вызовов, если у отладчика нет условной возможности точки останова)
- Проще для прочтения
- Легче понять и, следовательно, легче поддерживать
- Фиксированная глубина: последовательность операторов «если даже если» может дать глубокое гнездование, что затрудняет компиляцию (особенно в автоматически сгенерированном коде)
- Легче убедиться, что все значения обрабатываются. Компиляторы могут выпустить предупреждение, если некоторые значения перечисления не обрабатываются.
Кроме того, оптимизированная реализация может выполняться гораздо быстрее, чем альтернатива, потому что она часто реализуется с помощью индексированной таблицы ветвей . [ 7 ] Например, определение потока программы на основе значения одного символа, если правильно реализовано, является гораздо более эффективным, чем альтернативная, значительно снижая длины пути инструкции . При реализации как таковой, оператор Switch, по сути, становится идеальным хэшем .
С точки зрения графика управления , оператор переключателя состоит из двух узлов (вход и выход), а также один край между ними для каждой опции. В отличие от этого, последовательность «если ... иначе, если ... если», если », имеет дополнительный узел для каждого случая, кроме первого и последнего, вместе с соответствующим преимуществом. Полученный график управления потоком для последовательностей «если» S, таким образом, имеет гораздо больше узлов и почти вдвое больше ребра, при этом они не добавляют какую-либо полезную информацию. Тем не менее, простые ветви в операторах IF индивидуально концептуально проще, чем сложная ветвь оператора коммутатора. С точки зрения цикломатической сложности , оба эти варианты увеличивают его на k -1, если приведены k случаи .
Переключение выражений
[ редактировать ]Выражения Switch представлены в Java SE 12 , 19 марта 2019 года в качестве предварительного просмотра.
Здесь выражение целого переключателя можно использовать для возврата значения.
Существует также новая форма этикетки, case L->
где правая сторона является единственным выражением.
Это также предотвращает падение и требует, чтобы случаи были исчерпывающими.
В Java SE 13 yield
Заявление представлено, и в Java SE 14 выражения переключателя становятся стандартной языковой функцией. [ 8 ] [ 9 ] [ 10 ] Например:
int ndays = switch (month) {
case JAN, MAR, MAY, JUL, AUG, OCT, DEC -> 31;
case APR, JUN, SEP, NOV -> 30;
case FEB -> {
if (year % 400 == 0) yield 29;
else if (year % 100 == 0) yield 28;
else if (year % 4 == 0) yield 29;
else yield 28; }
};
Альтернативное использование
[ редактировать ]Многие языки оценивают выражения внутри switch
Блоки во время выполнения, позволяя нескольким менее очевидным применению для конструкции. Это запрещает определенные оптимизации компилятора, поэтому чаще встречается на языках динамических и сценариев, где повышенная гибкость более важна, чем накладные расходы на производительность.
PHP
[ редактировать ]Например, в PHP может использоваться константа в качестве «переменной», и будет выполнено первое утверждение, которое оценивается в эту константу:
switch (true) {
case ($x == 'hello'):
foo();
break;
case ($z == 'howdy'): break;
}
switch (5) {
case $x: break;
case $y: break;
}
Эта функция также полезна для проверки нескольких переменных по одному значению, а не одной переменной по многим значениям.
COBOL также поддерживает эту форму (и другие формы) в EVALUATE
заявление.
PL/I имеет альтернативную форму SELECT
утверждение, где управляющее выражение вообще опущено, и первое WHEN
Это оценивается в True, выполняется.
Рубин
[ редактировать ]В Руби , из -за его обращения ===
Равенство, оператор может использоваться для тестирования для класса переменной:
case input
when Array then puts 'input is an Array!'
when Hash then puts 'input is a Hash!'
end
Руби также возвращает значение, которое может быть назначено переменной, и на самом деле не требует case
иметь какие -либо параметры (действуя немного как else if
заявление):
catfood =
case
when cat.age <= 1
junior
when cat.age > 10
senior
else
normal
end
Ассемблер
[ редактировать ]Оператор переключения на языке сборки :
switch:
cmp ah, 00h
je a
cmp ah, 01h
je b
jmp swtend ; No cases match or "default" code here
a:
push ah
mov al, 'a'
mov ah, 0Eh
mov bh, 00h
int 10h
pop ah
jmp swtend ; Equivalent to "break"
b:
push ah
mov al, 'b'
mov ah, 0Eh
mov bh, 00h
int 10h
pop ah
jmp swtend ; Equivalent to "break"
...
swtend:
Питон
[ редактировать ]Для Python 3.10.6 были приняты PEPS 634-636, что добавило match
и case
ключевые слова. [ 11 ] [ 12 ] [ 13 ] [ 14 ] В отличие от других языков, Python, в частности, не демонстрирует осеннего поведения.
letter = input("Put in a single letter: ").strip()[0].casefold() # first non-whitespace character of the input, lowercase
match letter:
case 'a' | 'e' | 'i' | 'o' | 'u': # Unlike conditions in if statements, the `or` keyword cannot be used here to differentiate between cases
print(f"Letter {letter} is a vowel!")
case 'y':
print(f"Letter {letter} may be a vowel.")
case _: # `case _` is equivalent to `default` from C and others
print(f"Letter {letter} is not a vowel!")
Обработка исключений
[ редактировать ]Ряд языков реализует форму оператора коммутатора при обработке исключений , когда, если исключение поднимается в блоке, выбирается отдельная ветвь, в зависимости от исключения. В некоторых случаях также присутствует филиал по умолчанию, если нет исключения, также присутствует. Ранним примером является Modula-3 , который использует TRY
... EXCEPT
Синтаксис, где каждый EXCEPT
определяет случай. Это также встречается в Delphi , Scala и Visual Basic .net .
Альтернативы
[ редактировать ]Некоторые альтернативы операторам переключения могут быть:
- Серия IF-ELSE условий , которые изучают целевое значение за раз. Поведение осеннего поведения может быть достигнуто с помощью последовательности условий , каждая из которых без предложения без других .
- Таблица поиска , которая содержит, как ключи,
case
значения и, как значения, часть подcase
заявление.
- (На некоторых языках только фактические типы данных разрешены в виде значений в таблице поиска. На других языках также можно назначить функции в виде значений таблицы поиска, набирая ту же гибкость, что и реальная
switch
заявление. См. Статью о управлении таблицей для более подробной информации об этом). - Lua не поддерживает операторы Case/Switch. [ 15 ] Эта техника поиска является одним из способов реализации
switch
заявления на языке Lua, у которого нет встроенныхswitch
. [ 15 ] - В некоторых случаях таблицы поиска более эффективны, чем не оптимизированные
switch
Операторы, поскольку многие языки могут оптимизировать поиск таблиц, тогда как операторы коммутатора не оптимизированы, если только диапазон значений не является небольшим с небольшим количеством пробелов. Неоптимизированный, не бинарный поиск , однако, почти наверняка будет медленнее, чем не оптимизированный переключатель или эквивалентные множественные операторы IF-ELSE . [ Цитация необходима ]
- (На некоторых языках только фактические типы данных разрешены в виде значений в таблице поиска. На других языках также можно назначить функции в виде значений таблицы поиска, набирая ту же гибкость, что и реальная
- Таблица управления (которая может быть реализована в виде простой таблицы поиска) также может быть настроена для размещения нескольких условий на нескольких входах, если это необходимо, и обычно демонстрирует большую «визуальную компактность», чем эквивалентный переключатель (который может занимать много операторов).
- Сопоставление рисунков , которое используется для реализации функциональности, подобной коммутатору, на многих функциональных языках.
Смотрите также
[ редактировать ]Ссылки
[ редактировать ]- ^ Скит, Джон (23 марта 2019 г.). C# в глубине . Мэннинг. ISBN 978-1617294532 .
- ^ Блох, Джошуа (2018). «Эффективная Java: Руководство по языку программирования» (третье изд.). Аддисон-Уэсли. ISBN 978-0134685991 .
- ^ «Определение по случаям», Клин 1952: 229
- ^ van der Linden, Peter (1994). Эксперт C Программирование: Deep C Secrets , p. 38. Prentice Hall, Eaglewood Cliffs. ISBN 0131774298 .
- ^ Со времени версии 4.0 , выпущенной в 2009 году.
- ^ Влад Лазаренко. От оператора переключения до машинного кода
- ^ Гюнтерот, Курт (27 апреля 2016 г.). Оптимизированный C ++ . О'Рейли СМИ. п. 182. ISBN 9781491922033 .
- ^ «JEP 325: выключатели коммутатора (предварительный просмотр)» . OpenJdk.java.net . Получено 2021-04-28 .
- ^ «JEP 354: Выключатель Switch (второй предварительный просмотр)» . OpenJdk.java.net . Получено 2021-04-28 .
- ^ "JEP 361: выключение вывода" . OpenJdk.java.net . Получено 2021-04-28 .
- ^ Галиндо Сальгадо, Пабло. «Что нового в Python 3.10» . Python 3.10.6 Документация . Получено 2022-08-19 .
- ^ Бухер, Брандт; Ван Россум, Гвидо (2020-09-12). «PEP 634 - Структурное сопоставление рисунков: спецификация» . Предложения по улучшению питона . Получено 2022-08-19 .
- ^ Кон, Тобиас ; Ван Россум, Гвидо (2020-09-12). «PEP 635 - Структурное соответствие рисунков: мотивация и обоснование» . Предложения по улучшению питона . Получено 2022-08-19 .
- ^ Моиссет, Даниэль Ф. "PEP 636 - Структурное соответствие рисунка: учебник" . Предложения по улучшению питона . Получено 2022-08-19 .
- ^ Jump up to: а беременный Оператор переключения в Lua
Дальнейшее чтение
[ редактировать ]- Стивен Клин , 1952 (10-я перепечатка 1991), Введение в метаматематику , издательская компания Северо-Голландии, Амстердам Н.Л. ISBN 0-7204-2103-9
- Джордж Буолос , Джон Берджесс и Ричард Джеффри , 2002 г., Компания и логика: Четвертое издание , издательство Кембриджского университета, Кембридж Великобритания, ISBN 0-521-00758-5 Мягкая обложка. CF Page 74-75.