WikiSort.ru - Не сортированное

ПОИСК ПО САЙТУ | о проекте

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

Обычно тернарная условная операция ассоциируется с операцией ?:, используемой в си-подобных языках программирования. На самом деле, подобные операции с другим синтаксисом имеются и во многих далёких по синтаксису от Си языках программирования. К наиболее популярным языкам, содержащим тернарную условную операцию, можно отнести C, 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)[1] вместо привычного теперь o1 ? o2 : o3. Прототипом же этой операции, в свою очередь, является условная функция cond языка Лисп, записываемая по правилам Лиспа в префиксной форме и имеющая произвольное количество аргументов.

Определение

Безотносительно к определённому языку программирования тернарную операцию можно определить так:

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

Алгоритм работы операции следующий:

  1. Вычисляется логическое выражение.
  2. Если логическое выражение истинно, то вычисляется значение выражения выражение 1, в противном случае — значение выражения выражение 2.
  3. Вычисленное значение возвращается.

Нужно обратить внимание, что вычисляется только одно из выражений: выражение 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 = $b==1 ? "first value" :
      ($b==2 ? "second value" :
      ($b==3 ? "result value" : "default value"));

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

//Первый пример
$result = isset($a) ? $a : 'DefaultValue';
//Второй пример
if ($result == 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]

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

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

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

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

Lua

Оператор реализован через логические операторы AND и OR. По определению языка, AND возвращает первый операнд, если он ЛОЖЬ или второй. Оператор OR возвращает первый операнд, если он ИСТИНА или второй. В языке Lua переменная с любым значением кроме nil и false считается ИСТИНОЙ. Используя эти правила и сцепив два оператора, получаем тернарный оператор:

x = (a < b) and a or b -- выбор минимального из двух чисел a и b

Расставим скобки, чтобы явно увидеть порядок вычислений:

x = ( (a < b) and a ) or b

Если выражение (a < b) истинно, то AND возвращает второй операнд - то есть а, далее выполняется оператор OR, для которого a будет ИСТИНА, поэтому результат всего выражения тоже будет a. Если проверяемое выражение ложно, то AND вернет ЛОЖЬ как операнд для OR, который в таком случае выдаст число b как результат выражения.

Haskell

Операция ветвления if в Haskell является условным выражением: else-выражение является обязательным и должно совпадать по типу с then-выражением. Также в стандартной библиотеке Data.Bool[7] есть функция 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"

Примечания

  1. BCPL Ternary operator (page 15). BCPL Reference Manual. Архивировано 31 марта 2012 года.
  2. Ю. Ю. Громов, С. И. Татаренко. 1.3.12. Условная операция // Программирование на языке си / Рецензент: профессор А. П. Афанасьев.
  3. Б. Страуструп. 7.13. Условная операция // Справочное руководство по C++.
  4. Оператор ?: (C#) // https://msdn.microsoft.com/ru-ru/library/ty67wk28.aspx
  5. Оператор If (Visual Basic) // https://msdn.microsoft.com/ru-ru/library/bb513985.aspx
  6. Оператор ? 1С 7.7 | Оператор
  7. Data.Bool. hackage.haskell.org. Проверено 29 апреля 2018.

Литература

Стефан Рэнди Дэвис, Чак Сфер. Глава 4. Операторы // C# 2005 для "чайников" = C# 2005 for dummies / под редакцией Т. Г. Сковородниковой. — М.-Спб.: Wiley, Диалектика, 2006. — С. 83. ISBN 5-8459-1068-4.

Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".

Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.

Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .




Текст в блоке "Читать" взят с сайта "Википедия" и доступен по лицензии Creative Commons Attribution-ShareAlike; в отдельных случаях могут действовать дополнительные условия.

Другой контент может иметь иную лицензию. Перед использованием материалов сайта WikiSort.ru внимательно изучите правила лицензирования конкретных элементов наполнения сайта.

2019-2024
WikiSort.ru - проект по пересортировке и дополнению контента Википедии