Тернарна умовна операція — Вікіпедія
Тернарна умовна операція (лат. ternarius — «потрійний») (зазвичай записується як ?:
) — у багатьох мовах програмування операція, яка повертає свій другий або третій операнд залежно від значення логічного виразу, заданого першим операндом. Як випливає з назви, тернарна операція приймає всього три вказаних операнди. Аналогом тернарної умовної операції в математичній логіці і булевій алгебрі є умовна диз'юнкція, яка записується у вигляді і реалізує алгоритм: «Якщо , то , інакше », що можна переписати як « або , залежно від або не ».
Зазвичай тернарна умовна операція асоціюється з операцією ?:
, яка використовується в сі-подібних мовах програмування. Насправді, подібні операції з іншим синтаксисом є і в багатьох далеких за синтаксисом від Сі мовах програмування. До найбільш популярних мов, що містять тернарну умовну операцію, можна віднести C, C++, JavaScript, Swift, Objective-C, C#, D, Java, Perl, PHP, Python, Tcl, Ruby, Verilog, Turbo Basic та інші. Своєю появою безпосередньо в тернарній формі ця операція зобов'язана мові Алгол-60, у якій вона мала синтаксис if o1 then o2 else o3
і потім мови BCPL (o1 -> o2, o3
)[1] замість звичного тепер o1 ? o2 : o3
. Прототипом цієї операції також є умовна функція cond
мови Лісп, яка записується за правилами Ліспа в префіксній формі і має довільну кількість аргументів.
Визначення[ред. | ред. код]
Безвідносно до певної мови програмування тернарну операцію можна визначити так:
логічний вираз ? вираз 1 : вираз 2
Алгоритм роботи операції наступний:
- Обчислюється
логічний вираз
. - Якщо
логічний вираз
істинний, то обчислюється значення виразувираз 1
, в іншому разі — значення виразувираз 2
. - Обчислене значення повертається.
Потрібно звернути увагу, що обчислюється тільки один з виразів: вираз 1
або вираз 2
. Це відповідає принципу лінивих обчислень, і зроблено не так для оптимізації, як для розширення можливостей: так, вираз x < 0 ? 0 : sqrt(x)
абсолютно коректний, незважаючи на те, що корінь з від'ємних чисел не береться.
Використання і реалізація[ред. | ред. код]
Тернарна умовна операція використовується у виразах для отримання одного з двох варіантів залежно від умови.
alarm_time = today in [SUNDAY, MONDAY] ? 12.00 : 8.00
У цьому прикладі умовного електронного будильника виставляється час, коли він повинен дзвонити, залежно від дня тижня. Потрібно зауважити, що приклад знову наведений для деякої абстрактної алгоритмічної мови програмування.
У наступному прикладі обчислюється значення найпростішого дельта-символу.
y = x == 0 ? 1 : 0
У наступному прикладі дана операція використана в ситуації, не пов'язаній з присвоюванням:
sprintf( Title, "%s %s", tv_system == TV_PAL ? "PAL" : "SECAM", tv_input ? Tv_Name[ tv_input - 1 ]: "TEST" );
У цьому разі еквівалентна конструкція з використанням if
—then
—else
вимагала б запису виклику функції sprintf
чотири рази. Або, як альтернатива, треба було б написати аналогічний за призначенням (але формально не еквівалентний) код з використанням двох додаткових змінних або декількох послідовних викликів sprintf
.
С[ред. | ред. код]
У Сі тернарна операція має наступний синтаксис:[2]
o1 ? o2 : o3
Як відомо,[кому?] у Сі немає логічного типу даних (у C99 з'явився логічний тип _Bool
). Тому операнд o1
повинен бути числом (цілим або дійсним) або вказівником. Спочатку обчислюється саме його значення. Воно порівнюється з нулем і, якщо воно не дорівнює нулю, обчислюється і повертається o2
, у разі рівності — o3
. Операнди o2
і o3
можуть бути різних, кажучи загалом, незбіжних типів, зокрема void
.
У наступному прикладі обчислюється мінімальне з чисел a
і b
:
min = (a < b) ? a : b;
C++[ред. | ред. код]
У C++ тернарна умовна операція має той самий синтаксис, що й у Сі.[3] Однак через наявність різниці між ініціалізацією і присвоюванням, бувають ситуації, коли операцію ?:
не можна замінити конструкцією 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
ініціалізується в момент оголошення результатом роботи тернарной операції. Подібного ефекту не вдалося б досягти простим присвоюванням у тому чи іншому випадку.
Крім того, тернарна умовна операція може бути застосована в лівій частині оператора присвоєння:
0. #include <iostream> 1. int main () 2. { 3. int a=0, b=0; 4. 5. const bool cond = ...; 6. (cond ? a : b) = 1; 7. std::cout << "a=" << a << ',' 8. << "b=" << b << '\n'; 9. }
У цьому прикладі, якщо логічна змінна cond
у рядку 5 міститиме значення true
, то значення 1 буде присвоєно змінній a
, інакше, воно буде присвоєно змінній b
.
Python[ред. | ред. код]
a = 42 b = 41 result = a if a > b else b assert result == 42
Також можна реалізувати через список:
[<вираз 1>, <вираз 2>][<умова>]
Повернеться результат вираз 1
, якщо умова хибна; і вираз 2
, якщо умова істинна. Якщо умова не буде булевими виразом, можливий вихід за межі списку з винятком.
PHP[ред. | ред. код]
$a = 1==0 ? "first value" : (2==0 ? "second value" : (3==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';
JavaScript[ред. | ред. код]
var a = 1==0 ? "first value" : 2==0 ? "second value" : 3==3 ? "result value" : "default value"
Ruby[ред. | ред. код]
Загальний синтаксис аналогічний C-подібним мовам.
print true ? "true" : "false" # Виведе true в стандартний вивід
C#[ред. | ред. код]
На тернарну операцію накладаються додаткові обмеження, пов'язані з типобезпекою. Вирази 1 і 2 повинні бути одного типу. Це призводить до наступного:
int a = 1; double b = 0.0; int nMax = (a>b) ? a : b;
Такий вихідний код не компілюватиметься незважаючи на те, що в кінцевому підсумку значення nMax
дорівнюватиме а
. Оскільки a
і b
повинні бути одного типу, a
підвищиться до double
, щоб відповідати b
. Тип результівного значення тернарної операції виявляється double
, і цей тип повинен бути знижений до int
під час присвоєння:[4]
int a = 1; double b = 0.0; int nMax; // Можна вчинити так: nMax = (int) ((a>b) ? a : b) ; // ...або так nMax = (a>b) ? a : (int)b;
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
, яка також для сумісності з попередніми версіями доступна розробнику.[5]
Turbo Basic[ред. | ред. код]
Синтаксис[6]: IF logic_expression [<> 0] [,] THEN statement(s) [ELSE statement(s)]
Будь-який результат logic_expression
не рівний 0 вважається %FALSE
, але не %TRUE
, рівний тільки -1. logic_expression
може бути числовим (numeric), так і символьним (string). У разі символьного виразу обчислення проводяться з ASCII-кодами символів.
%TRUE = -1 %FALSE = 0 A$ = "M" B$ = "N" C! = 43 D# = 44 IF A$>B$ <> %FALSE, THEN RESULT# = C! ELSE RESULT# = D# PRINT RESULT#
За допомогою функції FN IfThenElse(X1,X2,X3)
, замість інфіксного виду тернарного оператора If Then X1 X2 Else X3
можна користуватися префіксним видом тернарного оператора IfThenElse
:
A$ = "M" B$ = "N" C! = 43 D# = 44 COND = A$<B$ 'COND = любое logic_expression PRINT "FN IfThenElse(X1,X2,X3) =";FN IfThenElse(COND,C!,D#) END DEF FN IfThenElse(X1,X2,X3) IF X1 <> 0 THEN FN IfThenElse = X2 ELSE FN IfThenElse = X3 END DEF
Примітки[ред. | ред. код]
- ↑ BCPL Ternary operator (page 15) (PDF). BCPL Reference Manual. Архів оригіналу (PDF) за 31 березня 2012. Процитовано 28 вересня 2017.
- ↑ Ю. Ю. Громов, С. И. Татаренко. Программирование на языке СИ.
- ↑ Б. Страуструп. Мова програмування С++.
- ↑ Оператор
?:
(C#) // https://msdn.microsoft.com/ru-ru/library/ty67wk28.aspx - ↑ Оператор If (Visual Basic) // https://msdn.microsoft.com/ru-ru/library/bb513985.aspx
- ↑ Borland Turbo BASIC Owners Handbook 1987
Ця стаття потребує додаткових посилань на джерела для поліпшення її перевірності. (жовтень 2017) |
Це незавершена стаття про мови програмування. Ви можете допомогти проєкту, виправивши або дописавши її. |