Для установки нажмите кнопочку Установить расширение. И это всё.

Исходный код расширения WIKI 2 регулярно проверяется специалистами Mozilla Foundation, Google и Apple. Вы также можете это сделать в любой момент.

4,5
Келли Слэйтон
Мои поздравления с отличным проектом... что за великолепная идея!
Александр Григорьевский
Я использую WIKI 2 каждый день
и почти забыл как выглядит оригинальная Википедия.
Статистика
На русском, статей
Улучшено за 24 ч.
Добавлено за 24 ч.
Что мы делаем. Каждая страница проходит через несколько сотен совершенствующих техник. Совершенно та же Википедия. Только лучше.
.
Лео
Ньютон
Яркие
Мягкие

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

Из Википедии — свободной энциклопедии

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

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

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

#include <iostream>
int main () 
{
    int a=0, b=0;

    const bool cond = ...;
    (cond ? a : b) = 1;
    std::cout << "a=" << a << ','
              << "b=" << b << '\n';
}

В этом примере, если логическая переменная 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 (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"

Rust

Rust использует конструкцию if expr1 else expr2 как замену традиционному тернарному оператору ?:;. Обратите внимание на отсутствие точки с запятой внутри блоков кода, и наличие точки с запятой в конце присваивания результата выражения y.

let x = 5;

let y = if x == 5 {
    10
} else {
    15
};

Эту же запись можно сделать в другом виде:

let y = if x == 5 { 10 } else { 15 }

Наличие фигурных скобок обязательно при использовании условных выражений в Rust.

Примечания

  1. BCPL Ternary operator (page 15) (недоступная ссылка). BCPL Reference Manual. Дата обращения: 8 мая 2009. Архивировано 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.

Эта страница в последний раз была отредактирована 17 марта 2021 в 07:47.
Основа этой страницы находится в Википедии. Текст доступен по лицензии CC BY-SA 3.0 Unported License. Нетекстовые медиаданные доступны под собственными лицензиями. Wikipedia® — зарегистрированный товарный знак организации Wikimedia Foundation, Inc. WIKI 2 является независимой компанией и не аффилирована с Фондом Викимедиа (Wikimedia Foundation).