К тройной или не к тройной?

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

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

+170
01 окт. '08 в 23:27
источник поделиться
54 ответа
  • 1
  • 2

Используйте его только для простых выражений:

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;
+213
01 окт. '08 в 23:58
источник

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

+112
01 окт. '08 в 23:34
источник

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

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

int count = (condition) ? 1 : 0;

является более сложным, чем это:

int count;

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

edit -

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

+76
11 февр. '09 в 1:37
источник

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

Я стараюсь использовать их больше в 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

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

+38
02 окт. '08 в 4:32
источник

Оператор Ternary ?: является просто функциональным эквивалентом процедурной конструкции 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) конечный результат не является особенно кратким.

+38
02 окт. '08 в 1:13
источник

Это вопрос стиля, действительно; подсознательные правила, к которым я склонен следовать, следующие:

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

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

+24
01 окт. '08 в 23:47
источник

Как и многие вопросы мнений, ответ неизбежно: это зависит от

Для чего-то вроде:

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. Хороший материал.

+18
11 февр. '09 в 1:42
источник

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

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

+12
01 окт. '08 в 23:29
источник

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

Другими способами, такими как читаемость, ремонтопригодность и DRY (Don't-Repeat-Yourself), любой выбор может оказаться лучше, чем другой.

+11
11 февр. '09 в 1:57
источник

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

Упрощенный пример:

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

или (спасибо, астерит)

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

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

+10
01 окт. '08 в 23:32
источник

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

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

+9
01 окт. '08 в 23:37
источник

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

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

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

+7
01 окт. '08 в 23:35
источник

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

+6
11 февр. '09 в 2:32
источник

(Взлом дня)

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

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

int b = IF(condition1)    res1
        ELSE IF(condition2)  res2
        ELSE IF(conditions3) res3
        ELSE res4;
+6
15 окт. '10 в 23:28
источник

Я думаю, что тройной оператор следует использовать, когда это необходимо. Это, очевидно, очень субъективный выбор, но я считаю, что простое выражение (особенно как выражение возврата) намного яснее, чем полный тест. Пример в 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: они ленивы и возвращает последнее значение, вычисленное, если оно равно конечному состоянию.

+5
01 окт. '08 в 23:39
источник

Я видел таких зверей, как (это было на самом деле намного хуже, так как оно было 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");
+5
11 февр. '09 в 1:48
источник

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

+5
11 февр. '09 в 1:48
источник

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

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");
}
+4
01 окт. '08 в 23:56
источник

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

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

Рассмотрим:

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;

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

+4
01 окт. '08 в 23:51
источник

Только когда:

$var = (simple > test? simple_result_1: simple_result_2);

ПОЦЕЛУЙ.

+3
02 окт. '08 в 0:43
источник

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

before:

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

after:

    drawtext(x,y,isheader==true?WHITE:BLUE,string);
+3
02 окт. '08 в 3:12
источник

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

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

+3
01 окт. '08 в 23:31
источник

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

int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

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

SomeType& ref = pInput ? *pInput : somethingElse;
+3
11 февр. '09 в 2:33
источник

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

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

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

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

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

+2
02 окт. '08 в 0:12
источник

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

Несомненно, в моей книге будет большой NO-NO.

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

+2
02 окт. '08 в 1:21
источник

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

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

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

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

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

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

+2
11 февр. '09 в 2:50
источник

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

+2
11 февр. '09 в 1:39
источник

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

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

+2
11 февр. '09 в 1:40
источник

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

expr ?: default

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

+2
02 окт. '08 в 14:18
источник

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

+2
01 окт. '08 в 23:33
источник
  • 1
  • 2

Посмотрите другие вопросы по меткам или Задайте вопрос