Главная
Новости
Строительство
Ремонт
Дизайн и интерьер




20.05.2022


20.05.2022


18.05.2022


18.05.2022


17.05.2022





Яндекс.Метрика

Тернарная условная операция

22.01.2022

Тернарная условная операция (от лат. ternarius — «тройной») — реализованная во многих языках программирования операция, возвращающая свой второй или третий операнд в зависимости от значения логического выражения, заданного первым операндом. Аналогом тернарной условной операции в математической логике и булевой алгебре является условная дизъюнкция, которая записывается в виде [ p , q , r ] {displaystyle [p,q,r]} и реализует алгоритм: «если q {displaystyle q} , то p {displaystyle p} , иначе r {displaystyle r} ».

Обычно тернарная условная операция ассоциируется с операцией ?:, используемой в си-подобных языках программирования. На самом деле, подобные операции с другим синтаксисом имеются и во многих далёких по синтаксису от Си языках программирования. Среди популярных языков, в синтаксис которых встроена тернарная условная операция — Си, C++, JavaScript, Objective-C, C#, D, Java, ECMAScript, Perl, PHP, Python,Tcl, Ruby, Verilog, Turbo Basic. Своим появлением непосредственно в тернарной инфиксной форме эта операция обязана языку Алгол-60, в котором она имела синтаксис if o1 then o2 else o3 и затем языку BCPL (o1 -> o2, o3) вместо привычного теперь o1 ? o2 : o3. Прототипом же этой операции, в свою очередь, является условная функция cond языка Лисп, записываемая по правилам Лиспа в префиксной форме и имеющая произвольное количество аргументов.

Обычно в реализацию операции закладывается вычисление условия и только одного из выражений, что обеспечивает в ряде случаев расширенные возможности, например, выражение x > 0 ? 0 : sqrt(x) считается корректным, несмотря на то, что из отрицательных чисел корень не берётся.

Примеры

Символ Кронекера:

y = x == 0 ? 1 : 0.

Минимальное из чисел a и b:

min = (a < b) ? a : b

Может быть использована в ситуации, не связанной с присваиванием:

sprintf( Title, "%s %s", tv_system == TV_PAL ? "PAL" : "SECAM", tv_input ? Tv_Name[ tv_input - 1 ]: "TEST" );

— в данном случае эквивалентная конструкция с использованием if-then-else потребовала бы записи вызова функции sprintf четыре раза.

Си-подобные языки

В базовом Си нет логического типа данных (в C99 появился логический тип _Bool), поэтому первый операнд должен быть числом (целым или вещественным) или указателем; сначала вычисляется именно его значение и сравнивается с нулём, и, если оно не равно нулю, вычисляется и возвращается второй операнд, в случае равенства — третий. Второй и третий операнды могут быть различных типов (включая void).

В C++ тернарная условная операция имеет тот же синтаксис, что и в Си, однако за счёт наличия разницы между инициализацией и присваиванием, бывают ситуации, когда операцию ?: нельзя заменить конструкцией if-then-else, как, например, в следующем случае:

#include <iostream> #include <fstream> #include <string> using namespace std; int main(int argc, char** argv) { string name; ofstream fout; if (argc > 1 && argv[1]) { name = argv[1]; fout.open(name.c_str(), ios::out | ios::app); } ostream& sout = name.empty() ? cout : fout; return 0; }

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

Кроме того, тернарная условная операция может быть применена в левой части оператора присвоения:

#include <iostream> int main () { int a=0, b=0; const bool cond = ...; (cond ? a : b) = 1; std::cout << "a=" << a << ',' << "b=" << b << ' '; }

В этом примере, если логическая переменная cond в строке 5 будет содержать значение true, то значение 1 будет присвоено переменной a, иначе, оно будет присвоено переменной b.

В C# на тернарную операцию накладываются дополнительные ограничения, связанные с типобезопасностью. Выражения 1 и 2 должны быть одного типа. Это приводит к следующему:

int a = 1; double b = 0.0; int nMax = (a>b) ? a : b;

Такой исходный код не будет компилироваться несмотря на то, что в конечном итоге значение nMax будет равно а. Поскольку a и b должны быть одного и того же типа, a повысится до double, чтобы соответствовать b. Тип результирующего значения тернарной операции оказывается double, и этот тип должен быть понижен до int при присваивании:

int a = 1; double b = 0.0; int nMax; // Можно поступить так: nMax = (int) ((a>b) ? a : b) ; // ...или так nMax = (a>b) ? a : (int)b;

Python

В Python используется синтаксис с применением ключевых слов if-else:

a = 42 b = 41 result = a if a > b else b assert result == 42

Также можно реализовать через список:

[<выражение 1>, <выражение 2>][<условие>]

— будет возвращён результат выражения 1, если условие ложно; и выражения 2, если условие истинно. Если условие будет не булевым выражением, возможен выход за границы списка с исключением.

PHP

В PHP используется си-подобный синтаксис:

$a = $b==1 ? "first value" : ($b==2 ? "second value" : ($b==3 ? "result value" : "default value"));

Тернарный оператор в PHP эквивалентен более длинной конструкции if — else. Следующие два примера эквивалентны:

//Первый пример $result = isset($a) ? $a : 'DefaultValue'; //Второй пример if (isset($a)) { $result = $a; } else { $result = 'DefaultValue'; }

Такие конструкции часто применяются чтобы в любом случае проинициализировать переменную для последующих вычислений (иначе PHP выдаст ошибку уровня E_NOTICE).

Начиная с версии 5.3 появилась возможность не указывать второй параметр операции. Например, две следующих записи эквивалентны:

$Variable = $_GET['Parameter'] ? $_GET['Parameter'] : 'DefaultValue'; $Variable = $_GET['Parameter'] ?: 'DefaultValue';

Visual Basic

В классической версии Visual Basic существует тернарный оператор в виде функции IIf(Expr, TruePart, FalsePart). Данная функция имеет особенность: при оценке выражения Expr, также будут вычисляться TruePart и FalsePart, вне зависимости от результата выражения: истинно оно или ложно. Это может привести к неожиданным результатам, а иногда и к замедлению выполнения кода, если в качестве возвращаемых значений будет вызов функций с длительными операциями.

Dim iCount As Long Public Sub Main() iCount = 1 MsgBox IIf(1 = 1, FuncYes, FuncNo) 'Переменная iCount будет содержать "3", т.к. обе функции будут выполнены MsgBox iCount End Sub Public Function FuncYes() As String iCount = iCount + 1 FuncYes = "Да" End Function Public Function FuncNo() As String iCount = iCount + 1 FuncNo = "Нет" End Function

Для замены функции IIf можно переписать выражение в одну строку, но это не будет являться аналогом функции, а будет всего лишь краткая форма записи оператора ветвления

If Expr Then TruePart Else FalsePart

С появлением VB.NET, в синтаксис языка был включен привычный тернарный оператор и записывается как If(Expr, TruePart, FalsePart). Данный оператор использует сокращенные вычисления, в отличие от функции IIf, которая также для совместимости с прошлыми версиями доступна разработчику.

Встроенный язык 1С

В языке конфигурирования платформы 1С:Предприятие тернарный оператор имеет синтаксис:

?(логическое выражение, выражение 1, выражение 2)

Широко применяется в качестве сокращенной записи конструкций Если <логическое выражение> Тогда ... Иначе ... КонецЕсли
В версии платформы 7.7 была возможность использования тернарного оператора в правой части оператора присваивания.

Haskell

В Haskell операция ветвления if является условным выражением: else-выражение является обязательным и должно совпадать по типу с then-выражением. Также в стандартной библиотеке Data.Bool есть функция bool, возвращающая одно из двух выражений в зависимости от значения предиката.

Тернарная операция в привычной форме может быть определена как инфиксная функция через сопоставление с образцом (указание типов не обязательно):

(?) :: Bool -> a -> a -> a (?) True a _ = a (?) False _ b = b

или через любую операцию ветвления, например if или case of:

(?) predicate thenExpr elseExpr = if predicate then thenExpr else elseExpr (?) predicate thenExpr elseExpr = case predicate of {True -> thenExpr; _ -> elseExpr}

Поскольку (?) — инфиксная (бинарная) функция, то она принимает первые 2 аргумента и возвращает функцию одного аргумента. Для её применения к третьему аргументу используется аппликация ($):

True ? "then" $ "else" > "then" False ? "then" $ "else" > "else"