В информатике условные операторы ( то есть условные операторы , условные выражения и условные конструкции ) — это конструкции языка программирования , которые выполняют различные вычисления или действия или возвращают различные значения в зависимости от значения логического выражения, называемого условием .
Условные операторы обычно реализуются путем выборочного выполнения инструкций. Хотя динамическая диспетчеризация обычно не классифицируется как условная конструкция, это еще один способ выбора между альтернативами во время выполнения .
Условные операторы — это императивные конструкции, выполняемые для побочного эффекта, в то время как условные выражения возвращают значения. Многие языки программирования (например, C) имеют отдельные условные операторы и условные выражения. Хотя в чистом функциональном программировании условные выражения не имеют побочных эффектов , многие языки с условными выражениями (например, Lisp) поддерживают условные побочные эффекты.
Конструкция if–then
or if–then–else
используется во многих языках программирования. Хотя синтаксис различается от языка к языку, базовая структура (в форме псевдокода ) выглядит следующим образом:
Если (булево условие) Тогда (последующий)Еще (альтернатива)Конец Если
Например:
Если запас=0 Тогда сообщение= заказать новый товарЕще сообщение= есть на складеКонец Если
В приведенном выше примере кода часть, представленная (логическим условием), представляет собой условное выражение , имеющее внутреннее значение (например, оно может быть заменено одним из значений True
или False
), но не имеющее внутреннего значения. Напротив, комбинация этого выражения, и If
, Then
окружающего его, и консеквента, который следует за ним, представляет собой условное утверждение , имеющее внутреннее значение (например, выражающее связное логическое правило), но не имеющее внутреннего значения.
Когда интерпретатор находит If
, он ожидает логическое условие – например, x > 0
, что означает «переменная x содержит число больше нуля» – и оценивает это условие. Если условие равно , выполняются true
операторы, следующие за . В противном случае выполнение продолжается в следующей ветви – либо в блоке (что обычно необязательно), либо, если ветви нет, то после .then
else
else
end If
После выполнения любой из ветвей управление возвращается к точке после end If
.
В ранних языках программирования, особенно в некоторых диалектах BASIC в домашних компьютерах 1980-х годов , if–then
оператор мог содержать только GOTO
операторы (эквивалентные инструкции ветвления ). Это привело к трудночитаемому стилю программирования, известному как спагетти-программирование , с программами в этом стиле, называемыми спагетти-кодом . В результате структурное программирование , которое позволяет (фактически) произвольным операторам помещаться в блоки операторов внутри оператора if
, приобрело популярность, пока не стало нормой даже в большинстве кругов программирования BASIC. Такие механизмы и принципы были основаны на более старом, но более продвинутом семействе языков ALGOL , и языки, подобные ALGOL, такие как Pascal и Modula-2, влияли на современные варианты BASIC в течение многих лет. Хотя возможно, используя только GOTO
операторы в if–then
операторах, писать программы, которые не являются спагетти-кодом и так же хорошо структурированы и читабельны, как программы, написанные на структурном языке программирования, структурное программирование упрощает это и обеспечивает это. Структурированные if–then–else
операторы, подобные приведенному выше примеру, являются одним из ключевых элементов структурного программирования и присутствуют в большинстве популярных языков программирования высокого уровня, таких как C , Java , JavaScript и Visual Basic .
Ключевое else
слово сделано для того, чтобы нацеливаться на определенный if–then
оператор, предшествующий ему, но для вложенных if–then
операторов классические языки программирования, такие как ALGOL 60, с трудом определяли, какой конкретный оператор следует нацеливать. Без четких границ для какого оператора какой, else
ключевое слово может нацеливаться на любой предшествующий if–then
оператор во вложенном состоянии, как проанализировано.
если а, то если б, то с, иначе с2
можно проанализировать как
если а, то ( если б, то с) иначе с2
или
если а то ( если б то с иначе с2)
в зависимости от того, else
связан ли с первым if
или вторым if
. Это известно как проблема висячего else и решается разными способами в зависимости от языка (обычно с помощью end if
оператора или {...}
скобок).
Используя else if
, можно объединить несколько условий. Будут выполнены только операторы, следующие за первым условием, которое будет признано истинным. Все остальные операторы будут пропущены.
если условие то -- операторы elseif условие то -- еще операторы elseif условие то -- еще операторы;...else -- другие операторы; конец if ;
Например, для магазина, предлагающего скидку на товар до 30%:
если скидка < 11% то распечатать (вам придется заплатить 30 долларов)elseif скидка<21% тогда распечатать (вам придется заплатить 20 долларов)elseif скидка<31% тогда распечатать (вам придется заплатить 10 долларов)конец, если ;
В приведенном выше примере, если скидка составляет 10%, то первый оператор if будет оценен как истинный и будет выведено сообщение «you have to pay $30». Все остальные операторы ниже первого оператора if будут пропущены.
Например elseif
, в языке Ada оператор является просто синтаксическим сахаром для else
following by if
. В Ada разница в том, что end if
требуется только один, если использовать elseif
вместо else
following by if
. PHP использует elseif
ключевое слово [1] как для своих фигурных скобок, так и для синтаксисов двоеточия. Perl предоставляет ключевое слово elsif
, чтобы избежать большого количества фигурных скобок, которые потребовались бы для множественных операторов if
and else
. Python использует специальное ключевое слово , elif
поскольку структура обозначается отступом, а не фигурными скобками, поэтому повторное использование else
and if
потребовало бы увеличения отступа после каждого условия. Некоторые реализации BASIC , такие как Visual Basic , [2] тоже используют ElseIf
. Аналогично, более ранние оболочки UNIX (позже объединенные в синтаксис оболочки POSIX [3] ) тоже используют elif , но предоставляют возможность разделения пробелами, переносами строк или и тем, и другим.
Однако во многих языках, более непосредственно произошедших от Algol, таких как Simula , Pascal , BCPL и C , этот специальный синтаксис для else if
конструкции отсутствует, как и во многих синтаксических производных C , таких как Java , ECMAScript и т. д. Это работает, поскольку в этих языках любой отдельный оператор (в данном случае ...) может следовать за условным оператором, не будучи заключенным в блок.if cond
Этот выбор дизайна имеет небольшую «стоимость». Каждая else if
ветвь фактически добавляет дополнительный уровень вложенности. Это усложняет работу компилятора (или людей, которые пишут компилятор), поскольку компилятор должен анализировать и реализовывать произвольно длинные else if
цепочки рекурсивно.
Если все термины в последовательности условных операторов проверяют значение одного выражения (например, if x=0
... else if x=1
... else if x=2
...), альтернативой является оператор switch , также называемый оператором case или оператором select. Наоборот, в языках, в которых нет оператора switch, они могут быть получены с помощью последовательности else if
операторов.
Многие языки поддерживают выражения if , которые похожи на операторы if, но возвращают значение в качестве результата. Таким образом, они являются истинными выражениями (которые оцениваются как значение), а не операторами (которые могут быть недопустимы в контексте значения).
АЛГОЛ 60 и некоторые другие члены семейства АЛГОЛ допускают if–then–else
в качестве выражения:
myvariable := если x > 20, то 1, иначе 2
В диалектах Lisp – Scheme , Racket и Common Lisp – первый из которых был в значительной степени вдохновлен ALGOL:
;; Схема ( define myvariable ( if ( > x 12 ) 1 2 )) ; Присваивает 'myvariable' значение 1 или 2, в зависимости от значения 'x'
;; Common Lisp ( let (( x 10 )) ( setq myvariable ( if ( > x 12 ) 2 4 ))) ; Присваивает 'myvariable' значению 2
В Haskell 98 есть только выражение if , нет оператора if , и эта else
часть обязательна, так как каждое выражение должно иметь некоторое значение. [4] Логика, которая в других языках выражалась бы с помощью условных операторов, обычно выражается с помощью сопоставления с образцом в рекурсивных функциях.
Поскольку Haskell ленив , можно записывать управляющие структуры, такие как if , как обычные выражения; ленивая оценка означает, что функция if может оценивать только условие и соответствующую ветвь (где строгий язык оценивал бы все три). Это можно записать так: [5]
если ' :: Bool -> a -> a -> a если ' True x _ = x если ' False _ y = y
В языках C и C-подобных есть специальный тернарный оператор ( ?: ) для условных выражений с функцией, которая может быть описана следующим шаблоном:
condition ? evaluated-when-true : evaluated-when-false
Это означает, что его можно встраивать в выражения, в отличие от операторов if, в языках типа C:
my_variable = x > 10 ? "foo" : "bar" ; // В языках типа C
что можно сравнить с выражениями if–then–else в языке Algol (в отличие от оператора ) (и аналогичными в Ruby и Scala, среди прочих).
Чтобы сделать то же самое с помощью оператора if, потребовалось бы более одной строки кода (согласно типичным соглашениям о компоновке) и потребовалось бы упомянуть «my_variable» дважды:
если ( x > 10 ) my_variable = "foo" ; иначе my_variable = "bar" ;
Некоторые утверждают, что явный оператор if/then легче читать и что он может компилироваться в более эффективный код, чем тернарный оператор, [6] в то время как другие утверждают, что краткие выражения легче читать, чем операторы, разбитые на несколько строк и содержащие повторения.
x = TextWindow.ReadNumber () If ( x > 10 ) Then TextWindow.WriteLine ( " Моя переменная называется 'foo'." ) Else TextWindow.WriteLine ( " Моя переменная называется 'bar'. " ) EndIf
Во-первых, когда пользователь запускает программу, появляется курсор, ожидающий, пока читатель введет число. Если это число больше 10, на экране отображается текст «Моя переменная называется 'foo'». Если число меньше 10, на экране печатается сообщение «Моя переменная называется 'bar'».
В Visual Basic и некоторых других языках предусмотрена функция IIf
, которая может использоваться как условное выражение. Однако она не ведет себя как истинное условное выражение, поскольку всегда оцениваются обе ветви: true и false; просто результат одной из них отбрасывается, а результат другой возвращается функцией IIf.
В Tcl if
это не ключевое слово, а функция (в Tcl известная как команда или proc
). Например
если { $x > 10 } { выводит "Фу!" }
вызывает функцию с именем, if
передавая 2 аргумента: первый — условие, а второй — истинная ветвь. Оба аргумента передаются как строки (в Tcl все, что находится в фигурных скобках, является строкой).
В приведенном выше примере условие не оценивается перед вызовом функции. Вместо этого реализация функции if
получает условие как строковое значение и отвечает за оценку этой строки как выражения в области действия вызывающего. [7]
Такое поведение возможно при использовании команд uplevel
и expr
:
Поскольку if
это на самом деле функция, она также возвращает значение:
В Rustif
всегда является выражением. Он вычисляется в значение любой выполненной ветви или в тип модуля , ()
если ветвь не выполнена. Если ветвь не предоставляет возвращаемого значения, она вычисляется в ()
по умолчанию. Чтобы гарантировать, что if
тип выражения известен во время компиляции, каждая ветвь должна вычисляться в значение того же типа. По этой причине ветвь else
фактически обязательна, если только другие ветви не вычисляются в ()
, потому что if
без else
всегда может вычисляться в ()
по умолчанию. [10]
// Присвоить my_variable некоторое значение в зависимости от значения x let my_variable = if x > 20 { 1 } else { 2 }; // Этот вариант не скомпилируется, так как 1 и () имеют разные типы let my_variable = if x > 20 { 1 }; // Значения можно опустить, если они не нужны , если x > 20 { println! ( "x больше 20" ); }
Язык защищенных команд (GCL) Эдсгера Дейкстры поддерживает условное выполнение как список команд, состоящий из булевского охранника (соответствующего условию ) и соответствующего ему оператора. В GCL оценивается ровно один из операторов, охранники которого истинны, но какой именно — произвольно. В этом коде
если G0 → S0 □ Г1 → С1... □ Гн → Снфи
G i - это охранники, а S i - это утверждения. Если ни один из охранников не истинен, поведение программы не определено.
GCL в первую очередь предназначен для рассуждений о программах, но похожие нотации реализованы в Concurrent Pascal и Occam .
До версии Fortran 77 в языке Fortran существовал арифметический оператор if , который переходил к одной из трех меток в зависимости от того, равен ли его аргумент e e < 0, e = 0, e > 0. Это был самый ранний условный оператор в Fortran. [11]
ЕСЛИ ( е ) метка1 , метка2 , метка3
Где e — любое числовое выражение (не обязательно целое число).
Это эквивалентно этой последовательности, где e вычисляется только один раз.
ЕСЛИ ( e.LT.0 ) GOTO метка1 ЕСЛИ ( e.EQ.0 ) GOTO метка2 ЕСЛИ ( e.GT.0 ) GOTO метка3
Арифметический оператор if является неструктурированным управляющим оператором и не используется в структурном программировании .
На практике было замечено, что большинство арифметических IF
выражений ссылаются на следующее выражение с одной или двумя метками.
Это был единственный оператор условного управления в оригинальной реализации Fortran на компьютере IBM 704. На этом компьютере код операции test-and-branch имел три адреса для этих трех состояний. Другие компьютеры имели бы регистры «флагов», такие как положительный, нулевой, отрицательный, четный, переполнение, перенос, связанные с последними арифметическими операциями, и использовали бы такие инструкции, как «Переход, если аккумулятор отрицательный», затем «Переход, если аккумулятор нулевой» или аналогичные. Обратите внимание, что выражение вычисляется только один раз , и в таких случаях, как целочисленная арифметика, где может произойти переполнение, флаги переполнения или переноса также учитывались бы.
В отличие от других языков, в Smalltalk условный оператор не является языковой конструкцией , а определяется в классе Boolean
как абстрактный метод, который принимает два параметра, оба замыкания . Boolean
имеет два подкласса, True
и False
, которые оба определяют метод, True
выполняя только первое замыкание, False
выполняя только второе замыкание. [12]
var = условие ifTrue: [ 'foo' ] ifFalse: [ 'bar' ]
JavaScript использует операторы if-else, аналогичные операторам в языках C. Булево значение принимается в скобках между зарезервированным ключевым словом if и левой фигурной скобкой.
if ( Math . random () < 0.5 ) { console . log ( "Выпал орел!" ); } else { console . log ( "Выпал решка!" ); }
В приведенном выше примере принимается условие, Math.random() < 0.5
которое выводит, true
если случайное значение с плавающей точкой между 0 и 1 больше 0,5. Оператор использует его для случайного выбора между выводом You got Heads!
или You got Tails!
на консоль. Операторы Else и else-if также могут быть соединены после фигурной скобки оператора, предшествующего ему, столько раз, сколько необходимо, как показано ниже:
var x = Math.random (); if ( x < 1 / 3 ) { console.log ( " Победил один человек!" ) ; } else if ( x < 2 / 3 ) { console.log ( " Победили два человека!" ); } else { console.log ( " Ничья среди трех участников!" ); }
В лямбда-исчислении концепция условного оператора if-then-else может быть выражена с помощью следующих выражений:
правда = λx. λy. xложь = λx. λy. yеслиТогдаЕльсе = (λc. λx. λy. (cxy))
Примечание : если ifThenElse переданы две функции как левое и правое условные операторы, необходимо также передать пустой кортеж () в результат ifThenElse, чтобы фактически вызвать выбранную функцию, в противном случае ifThenElse просто вернет объект функции без вызова.
В системе, где числа могут использоваться без определения (например, Lisp, традиционная бумажная математика и т. д.), вышеизложенное можно выразить в виде одного замыкания ниже:
(( λистина. λложь. λеслиТогда. ( еслиТогда истина 2 3 ) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))
Здесь true, false и ifThenElse привязаны к своим соответствующим определениям, которые передаются в их область действия в конце их блока.
Действующая аналогия JavaScript (использующая только функции одной переменной для строгости) выглядит следующим образом:
var computingResult = (( _true => _false => _ifThenElse => _ifThenElse ( _true )( 2 )( 3 ) )( x => y => x )( x => y => y )( c => x => y => c ( x )( y )));
Приведенный выше код с многопеременными функциями выглядит следующим образом:
var computingResult = (( _true , _false , _ifThenElse ) => _ifThenElse ( _true , 2 , 3 ) )(( x , y ) => x , ( x , y ) => y , ( c , x , y ) => c ( x , y ));
Ниже приведена еще одна версия предыдущего примера без системы, где предполагаются числа.
В первом примере показана первая ветвь, а во втором — вторая ветвь.
(( λистина. λложь. λеслиТогдаЕльсе. ( еслиТогдаЕльсе истина ( λПерваяВетка. ПерваяВетка ) ( λВтораяВетка. ВтораяВетка )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r )) (( λистина. λложь. λеслиТогдаЕльсе. ( еслиТогдаЕльсе ложь ( λПерваяВетка. ПерваяВетка ) ( λВтораяВетка. ВтораяВетка )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))
Smalltalk использует похожую идею для своих истинных и ложных представлений, при этом True и False являются одиночными объектами, которые по-разному реагируют на сообщения ifTrue/ifFalse.
Раньше Haskell использовал именно эту модель для своего логического типа, но на момент написания большинство программ на Haskell использовали синтаксический сахар — конструкцию «if a then b else c», которая, в отличие от ifThenElse, не компонуется, если только не обернута в другую функцию или не реализована повторно, как показано в разделе Haskell этой страницы.
Операторы switch (в некоторых языках операторы case или многоканальные ветвления) сравнивают заданное значение с указанными константами и выполняют действие в соответствии с первой совпавшей константой. Обычно есть положение для действия по умолчанию ('else','internal'), которое будет выполнено, если совпадение не будет успешным. Операторы switch могут допускать оптимизации компилятора , такие как таблицы поиска . В динамических языках случаи могут не ограничиваться константными выражениями и могут распространяться на сопоставление с шаблоном , как в примере скрипта оболочки справа, где '*)' реализует случай по умолчанию как регулярное выражение, совпадающее с любой строкой.
Сопоставление с образцом можно рассматривать как альтернативу операторам if–then–else и case . Оно доступно во многих языках программирования с функциями функционального программирования, таких как Wolfram Language , ML и многих других. Вот простой пример, написанный на языке OCaml :
сопоставить фрукты с | "apple" -> приготовить пирог | "coconut" -> приготовить dango_mochi | "banana" -> смешать ;;
Сила сопоставления с образцом заключается в возможности сжато сопоставлять не только действия, но и значения с образцами данных. Вот пример, написанный на Haskell , который иллюстрирует обе эти возможности:
карта _ [] = [] карта f ( h : t ) = f h : карта f t
Этот код определяет функцию map , которая применяет первый аргумент (функцию) к каждому из элементов второго аргумента (списка) и возвращает результирующий список. Две строки — это два определения функции для двух видов аргументов, возможных в этом случае — один, когда список пуст (просто возвращается пустой список), и другой случай, когда список не пуст.
Сопоставление с образцом, строго говоря, не всегда является конструкцией выбора, поскольку в Haskell можно написать только одну альтернативу, которая гарантированно всегда будет сопоставлена – в этой ситуации она не используется как конструкция выбора, а просто как способ привязать имена к значениям. Однако она часто используется как конструкция выбора в языках, в которых она доступна.
В языках программирования, имеющих ассоциативные массивы или сопоставимые структуры данных, таких как Python , Perl , PHP или Objective-C , их использование для реализации условного присваивания является идиоматичным. [13]
pet = input ( "Введите тип питомца, которому вы хотите дать имя: " ) known_pets = { "Собака" : "Фидо" , "Кошка" : "Мяусс" , "Птица" : "Твити" , } my_name = known_pets [ pet ]
В языках, которые имеют анонимные функции или позволяют программисту назначать именованную функцию ссылке на переменную, условный поток может быть реализован с использованием хэша в качестве таблицы диспетчеризации .
Альтернативой инструкциям условного перехода является предикация . Предикация — это архитектурная особенность, которая позволяет выполнять инструкции условно, а не изменять поток управления .
Эта таблица относится к последней спецификации языка для каждого языка. Для языков, не имеющих спецификации, ссылаются на последнюю официально выпущенную реализацию.
else if
case
конструкции Ruby сопоставление регулярных выражений является одной из доступных альтернатив условного управления потоком. Для примера см. этот вопрос Stack Overflow.CASE
CASE WHEN cond1 THEN expr1 WHEN cond2 THEN expr2 [...] ELSE exprDflt END
if ... else if ... else
CASE
CASE expr WHEN val1 THEN expr1 [...] ELSE exprDflt END
if
устарела в Fortran 90.