На Троицу или не на Троицу? [закрытый]


Я лично сторонник тернарного оператора: () ? : ; Я понимаю, что он имеет свое место, но я столкнулся со многими программистами, которые полностью против его использования, а некоторые используют его слишком часто.

каковы ваши чувства по этому поводу? Какой интересный код вы видели, используя его?

30 172

30 ответов:

использовать простые выражения только:

int a = (b > 10) ? c : d;

не цепочка или гнездо тернарные операторы, как это трудно читать и сбивает с толку:

int a = b > 10 ? c < 20 ? 50 : 80 : e == 2 ? 4 : 8;

кроме того, при использовании тернарного оператора рассмотрите форматирование кода таким образом, чтобы улучшить читаемость:

int a = (b > 10) ? some_value                 
                 : another_value;

Это делает отладку немного сложнее, так как вы не можете разместить точки останова на каждом из вложенных выражений. Я использую его редко.

Я люблю их, особенно в типобезопасных языках.

Я не вижу, как это:

int count = (condition) ? 1 : 0;

- это сложнее, чем это:

int count;

if (condition)
{
  count = 1;
} 
else
{
  count = 0;
}

edit -

Я бы сказал, что тернарные операторы делают все менее сложным и более аккуратным, чем альтернатива.

прикованный я в порядке с-вложенный, не так много.

Я склонен использовать их больше в C просто b / c они являются оператором if, который имеет значение, поэтому он сокращает ненужные повторения или переменные:

x = (y < 100) ? "dog" :
    (y < 150) ? "cat" :
    (y < 300) ? "bar" : "baz";

, а не

     if (y < 100) { x = "dog"; } 
else if (y < 150) { x = "cat"; }
else if (y < 300) { x = "bar"; } 
else              { x = "baz"; }

в таких заданиях, как это, я нахожу, что это меньше для рефакторинга, и яснее.

когда я работаю в ruby с другой стороны, я, скорее всего, использовать if...else...end потому что это выражение тоже.

x =   if (y < 100) then "dog"
    elif (y < 150) then "cat"
    elif (y < 300) then "bar"
    else                "baz"
    end

(хотя, по общему признанию, для чего-то такого простого я мог бы просто использовать тернарный оператор в любом случае).

Троичной ?: оператор-это просто функциональный эквивалент процедурного if строительство. Так что пока вы не используете вложенные ?: выражения, аргументы за / против функционального представления любой операции применяются здесь. Но вложенные тернарные операции могут привести к совершенно запутанному коду (упражнение для читателя: попробуйте написать парсер, который будет обрабатывать вложенные тернарные условные обозначения, и вы оцените их сложность).

но есть много ситуаций, когда консервативное использование ?: оператор может привести к коду, который на самом деле легче читать, чем в противном случае. Например:

int compareTo(Object object) {
    if((isLessThan(object) && reverseOrder) || (isGreaterThan(object) && !reverseOrder)) {
       return 1;
    if((isLessThan(object) && !reverseOrder) || (isGreaterThan(object) && reverseOrder)) {
       return -1;
    else
      return 0;              
}

теперь сравните с этим:

int compareTo(Object object) {
    if(isLessThan(object))
        return reverseOrder ? 1 : -1;         
    else(isGreaterThan(object))
        return reverseOrder ? -1 : 1;
    else        
       return 0;              
}

поскольку код более компактен, он имеет меньше синтаксического шума, и при использовании тернарного оператора разумно (то есть только в отношении reverseOrder свойство) конечный результат не особенно немногословен.

это вопрос стиля, на самом деле; подсознательные правила, которым я склонен следовать:

  • только оценить 1 выражение-так foo = (bar > baz) ? true : false, но не foo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
  • если я использую его для отображения логики, например <%= (foo) ? "Yes" : "No" %>
  • только действительно использовать его для работы; не логики (так и не (foo) ? FooIsTrue(foo) : FooIsALie(foo)) логика потока в троичном сама по себе ложь, игнорируйте этот последний пункт.

мне это нравится, потому что это лаконично и элегантно для простых операция присваивания.

как и многие другие вопросы мнения, ответ неизбежно: зависит

, например:

return x ? "Yes" : "No";

Я думаю, что это много более кратким (и быстрее для меня, чтобы разобрать), чем:

if (x) {
    return "Yes";
} else {
    return "No";
}

теперь, если ваше условное выражение является сложным, то тернарная операция не является хорошим выбором. Что-то вроде:

x && y && z >= 10 && s.Length == 0 || !foo

не является хорошим кандидатом для тернарного оператора.

как кроме того, если вы программист C, GCC на самом деле имеет расширение это позволяет исключить часть if-true тернарного типа, например:

/* 'y' is a char * */
const char *x = y ? : "Not set";

который установит x до y предполагая, что y не NULL. Хороший материал.

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

в других случаях, кажется, что тернарный оператор уменьшает ясность.

мера цикломатическая сложность использование if операторы или тернарный оператор эквивалентны. Так что по этой мере ответ нет сложность будет точно так же, как и раньше.

по другим показателям, таким как читаемость, ремонтопригодность и сухость (не повторяйте себя), любой выбор может оказаться лучше, чем другой.

Я использую его довольно часто в тех местах, где я вынужден работать в конструкторе - например, в новых конструкциях .NET 3.5 LINQ to XML - для определения значений по умолчанию, когда необязательный параметр равен null.

пример:

var e = new XElement("Something",
    param == null ? new XElement("Value", "Default")
                  : new XElement("Value", param.ToString())
);

или (Спасибо asterite)

var e = new XElement("Something",
    new XElement("Value",
        param == null ? "Default"
                      : param.ToString()
    )
);

независимо от того, используете ли вы тернарный оператор или нет, важно убедиться, что ваш код читается. Любую конструкцию можно сделать нечитаемой.

Я использую тернарный оператор, где только могу, если это не делает код чрезвычайно трудным для чтения, но тогда это обычно просто признак того, что мой код может использовать небольшой рефакторинг.

меня всегда озадачивает, как некоторые люди думают, что тернарный оператор является "скрытой" функцией или несколько загадочной. Это одна из первых вещей, которые я узнал, когда начал программировать на C, и я не думаю, что это уменьшает читаемость вообще. Это естественная часть языка.

Я согласен с jmulder: он не должен использоваться вместо a if, но он имеет свое место для возвращения выражении или в выражении:

echo "Result: " + n + " meter" + (n != 1 ? "s" : "");
return a == null ? "null" : a;

первый просто пример, лучше i18n поддержка множественного числа должна быть использована!

Если вы используете тернарный оператор для простого условного назначения, я думаю, что это нормально. Я видел, что он (ab)используется для управления потоком программ, даже не делая назначения, и я думаю, что этого следует избегать. В этих случаях используйте оператор if.

(Хак дня)

#define IF(x) x ?
#define ELSE :

тогда вы можете сделать if-then-else как выражение:

int b = IF(condition1)    res1
        ELSE IF(condition2)  res2
        ELSE IF(conditions3) res3
        ELSE res4;

Я думаю, что тернарный оператор должен использоваться, когда это необходимо. Очевидно, что это очень субъективный выбор, но я нахожу, что простое выражение (особенно как возвращаемое выражение) намного яснее, чем полный тест. Пример в C / C++:

return (a>0)?a:0;

по сравнению с:

if(a>0) return a;
else return 0;

у вас также есть случай, когда решение находится между тернарным оператором и созданием функции. Например в Python:

l = [ i if i > 0 else 0 for i in lst ]

альтернатива:

def cap(value):
    if value > 0:
        return value
    return 0
l = [ cap(i) for i in lst ]

Это достаточно необходимо, чтобы в Python (в качестве примера) такую идиому можно было видеть регулярно:

l = [ ((i>0 and [i]) or [0])[0] for i in lst ]

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

Они мне нравятся. Не знаю почему, но я чувствую себя очень круто, когда использую троичное выражение.

Я видел таких зверей, как (это было на самом деле намного хуже, так как это было isValidDate и проверено месяц и день, но я не мог беспокоиться, пытаясь вспомнить все это):

isLeapYear =
    ((yyyy % 400) == 0)
    ? 1
    : ((yyyy % 100) == 0)
        ? 0
        : ((yyyy % 4) == 0)
            ? 1
            : 0;

где, очевидно, серия if-утверждений была бы лучше (хотя это все еще лучше, чем версия макроса, которую я когда-то видел).

Я не возражаю против таких мелочей, как:

reportedAge = (isFemale && (Age >= 21)) ? 21 + (Age - 21) / 3 : Age;

или даже немного хитрые вещи как:

printf ("Deleted %d file%s\n", n, (n == 1) ? "" : "s");

Мне нравится использовать оператор в коде отладки для печати значений ошибок, поэтому мне не нужно искать их все время. Обычно я делаю это для отладочных отпечатков, которые не останутся, как только я закончу разработку.

int result = do_something();
if( result != 0 )
{
  debug_printf("Error while doing something, code %x (%s)\n", result,
                result == 7 ? "ERROR_YES" :
                result == 8 ? "ERROR_NO" :
                result == 9 ? "ERROR_FILE_NOT_FOUND" :
                "Unknown");
}

я почти никогда не использую тернарный оператор, потому что всякий раз, когда я его использую, он всегда заставляет меня думать намного больше, чем я должен позже, когда я пытаюсь его поддерживать.

мне нравится избегать многословия, но когда это делает код намного проще подобрать, я пойду на многословие.

считаем:

String name = firstName;

if (middleName != null) {
    name += " " + middleName;
}

name += " " + lastName;

Теперь, это немного многословно, но я нахожу его гораздо более читаемым, чем:

String name = firstName + (middleName == null ? "" : " " + middleName)
    + " " + lastName;

или:

String name = firstName;
name += (middleName == null ? "" : " " + middleName);
name += " " + lastName;

кажется, что он тоже сжимается много информации в слишком маленьком пространстве, не давая понять, что происходит. Каждый раз, когда я вижу, что используется тернарный оператор, Я всегда находил альтернативу, которая казалась намного легче читать... опять же, это чрезвычайно субъективное мнение, поэтому, если вы и ваши коллеги находите тернарный очень читаемым, идите на это.

ну, синтаксис для него ужасен. Я нахожу функциональный ifs очень полезным, и часто делает код более читаемым.

Я бы предложил сделать макрос, чтобы сделать его более читаемым, но я уверен, что кто-то может придумать ужасный крайний случай (как всегда бывает с CPP).

когда:

переменной$var = (простой тест>? simple_result_1: simple_result_2);

поцелуй.

Я обычно использую в таких вещах:

before:

if(isheader)
    drawtext(x,y,WHITE,string);
else
    drawtext(x,y,BLUE,string);

after:

    drawtext(x,y,isheader==true?WHITE:BLUE,string);

как указывали другие, они хороши для коротких простых условий. Мне особенно нравятся они по умолчанию (вроде как |/ и или использование в javascript и python), например

int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

еще одним распространенным использованием является инициализация ссылки в C++. Поскольку ссылки должны быть объявлены и инициализированы в одном операторе, вы не можете использовать оператор if.

SomeType& ref = pInput ? *pInput : somethingElse;

Я отношусь к тернарным операторам очень похоже на GOTO. Они имеют свое место, но это то, чего вы обычно должны избегать, чтобы сделать код более понятным.

недавно я видел вариацию на тернарных операторах (ну, вроде), которые делают стандарт " ()? : "вариант кажется образцом ясности:

var Result = [CaseIfFalse, CaseIfTrue][(boolean expression)]

или, чтобы дать более ощутимый пример:

var Name = ['Jane', 'John'][Gender == 'm'];

имейте в виду, что это Javascript, поэтому такие вещи могут быть невозможны на других языках (к счастью).

для простых случаев, если мне нравится его использовать. На самом деле это гораздо легче читать код, например, в качестве параметров для функции или тому подобное. Также, чтобы избежать новой линии, которую я хотел бы сохранить со всеми моими if / else.

Neseting это было бы большое НЕТ-НЕТ в моей книге.

Итак, возобновляя, для одного if / else я буду использовать тернарный оператор. Для других случаев обычный if / else if / else (или switch)

Мне нравится особый случай Groovy тернарного оператора, называемый оператором Элвиса: ?:

expr ?: default

этот код вычисляется как expr, если он не равен null, и по умолчанию, если это так. Технически это не совсем тернарный оператор, но он определенно связан с ним и экономит много времени/ввода.

для простых задач, таких как присвоение другого значения в зависимости от условия, они велики. Я бы не использовал их, когда есть более длинные выражения в зависимости от условия tho.

так много ответов сказали,зависит. Я считаю, что если троичное сравнение не видно при быстром сканировании кода, то его не следует использовать.

в качестве побочного вопроса я мог бы также отметить, что само его существование на самом деле является немного аномалией из-за того, что в C сравнительное тестирование является утверждением. В значке, то if конструкция (как и большинство значков) на самом деле является выражением. Так что вы можете делать такие вещи, как:

x[if y > 5 then 5 else y] := "Y" 

... который я нахожу гораздо более читаемый, чем оператор сравнения тернери. : -)

тут недавно была дискуссия о возможности добавления ?: оператор к значку, но несколько человек правильно указали, что не было абсолютно никакой необходимости из-за пути if строительство.

это означает, что если бы вы могли сделать это на C (или на любом другом языке, который имеет оператор тернери), то вам вообще не нужен оператор тернери.

Если вы и ваши коллеги понимают, что они делают, и они не создаются в массовых группах, я думаю, что они делают код менее сложным и легче читать, потому что есть просто меньше кода.

единственный раз, когда я думаю, что тернарные операторы делают код сложнее понять, когда у вас есть более 3 или 4 в одной строке. Большинство людей не помнят, что они правы на основе приоритета, и когда у вас есть стек из них, это делает чтение кода кошмаром.