Преимущества использования условного: (тернарного) оператора



каковы преимущества и недостатки?: оператор в отличие от стандартного оператора if-else. Очевидные из них:



условное ?: Оператор




  • короче и лаконичнее при работе с прямыми сравнениями значений и назначений

  • не кажется таким гибким, как if/else construct


Стандартный If / Else




  • можно применить к другие ситуации (например, вызовы функций)

  • часто бывают излишне длинными


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

1488   17  

17 ответов:

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

хороший пример:

int result = Check() ? 1 : 0;

плохой пример:

int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;

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

в таких языках, как C++ и C#, вы можете определить локальные поля только для чтения (в теле метода), используя их. Это невозможно с обычным оператором if / then, потому что значение поля readonly должно быть назначено в пределах этого единственного оператора:

readonly int speed = (shiftKeyDown) ? 10 : 1;

это не то же, что:

readonly int speed;  
if (shifKeyDown)  
    speed = 10;    // error - can't assign to a readonly
else  
    speed = 1;     // error  

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

MoveCar((shiftKeyDown) ? 10 : 1);

...может генерировать меньше кода, чем при вызове одного и того же метода дважды:

if (shiftKeyDown)
    MoveCar(10);
else
    MoveCar(1);

конечно, это также более удобная и лаконичная форма (меньше ввода, меньше повторений и может уменьшить вероятность ошибок, если вам нужно дублировать куски кода в если/иначе). В чистых случаях "общего шаблона", как это:

object thing = (reference == null) ? null : reference.Thing;

... это просто быстрее читать / анализировать/понимать (как только вы привыкнете к нему), чем длиннофокусный эквивалент if / else, поэтому он может помочь вам быстрее "Грок" код.

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

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

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

if (a > 0)
    answer = compute(a, b, c, d, e);
else
    answer = compute(-a, b, c, d, e);

С помощью тернарного оператора это можно сделать следующим образом.

answer = compute(a > 0 ? a : -a, b, c, d, e); 

действительно классное использование:

x = foo ? 1 :
    bar ? 2 :
    baz ? 3 :
          4;

условный оператор отлично подходит для короткой условий такой:

varA = boolB ? valC : valD;

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

doSomeStuffToSomething(shouldSomethingBeDone()
    ? getTheThingThatNeedsStuffDone()
    : getTheOtherThingThatNeedsStuffDone());

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

if (shouldSomethingBeDone()) {
    doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
    doSomeAdditionalStuff();
} else {
doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}

или добавить еще одно условие:

if (shouldSomethingBeDone()) {
    doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
    doSomeAdditionalStuff();
} else if (shouldThisOtherThingBeDone()){
    doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}

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

(все глаза-скомпилированный код)

одна вещь, чтобы распознать при использовании тернарного оператора, что это выражение, а не оператор.

в функциональных языках, таких как scheme, различие не существует:

(Если (> a b) a b)

условное ?: Оператор "Не кажется таким гибким, как конструкция if / else"

в функциональных языках это.

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

хотя приведенные выше ответы действительны, и я согласен с тем, что читаемость важна, есть еще 2 момента для рассмотрения:

  1. в C#6, Вы можете иметь методы выражения тела.

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

string GetDrink(DayOfWeek day) 
   => day == DayOfWeek.Friday
      ? "Beer" : "Tea";
  1. поведение отличается, когда речь заходит о неявном преобразовании типов.

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

T GetT() => true ? new T1() : new T2();

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

С другой стороны,if/else версия ниже работает:

T GetT()
{
   if (true) return new T1();
   return new T2();
}

, потому что T1 превращается в T и так T2

иногда это может сделать назначение значения bool легче читать на первый взгляд:

// With
button.IsEnabled = someControl.HasError ? false : true;

// Without
button.IsEnabled = !someControl.HasError;

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

дальнейший интерес для вас может быть ?? оператор.

преимущество условного оператора заключается в том, что он является оператором. Другими словами, он возвращает значение. Так как if - Это заявление, он не может возвращать значение.

Я бы рекомендовал ограничить использование троичной(?:) оператор для простого однострочного назначения логики if/else. Что-то похожее на эту картину:

if(<boolCondition>) {
    <variable> = <value>;
}
else {
    <variable> = <anotherValue>;
}

может быть легко преобразован в:

<variable> = <boolCondition> ? <value> : <anotherValue>;

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

есть некоторые преимущества производительности с помощью the ? оператор в например. MS Visual C++, но это действительно специфическая вещь для компилятора. Компилятор может фактически оптимизировать условную ветвь в некоторых случаях.

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

return someIndex < maxIndex ? someIndex : maxIndex;

Это действительно единственные места, где я нахожу это хорошим, но для них я делаю.

хотя, если вы ищете логическое значение, это может иногда выглядеть как подходящая вещь:

bool hey = whatever < whatever_else ? true : false;

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

bool hey = (whatever < whatever_else);

Если вам нужно несколько ветвей на одном условии, используйте if:

if (A == 6)
  f(1, 2, 3);
else
  f(4, 5, 6);

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

f( (A == 6)? 1: 4, (B == 6)? 2: 5, (C == 6)? 3: 6 );

кроме того, вы можете использовать тернарный оператор при инициализации.

const int i = (A == 6)? 1 : 4;

делать это с if очень грязно:

int i_temp;
if (A == 6)
   i_temp = 1;
else
   i_temp = 4;
const int i = i_temp;

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

тернарный оператор может быть включен в rvalue, тогда как if-then-else не может; с другой стороны, if-then-else может выполнять циклы и другие операторы, тогда как тернарный оператор может выполнять только (возможно, void) rvalues.

в соответствующей заметке операторы && и | / допускают некоторые шаблоны выполнения, которые сложнее реализовать с помощью if-then-else. Например, если у вас есть несколько функций для вызова и вы хотите выполнить часть кода, если какой-либо из них не удастся, он может сделайте красиво с помощью оператора&&. Выполнение этого без этого оператора потребует либо избыточного кода, либо goto, либо дополнительной переменной флага.

С C# 7, вы можете использовать новый ref locals функция для упрощения условного назначения ref-совместимых переменных. Так что теперь, не только вы можете сделать:

int i = 0;

T b = default(T), c = default(T);

// initialization of C#7 'ref-local' variable using a conditional r-value⁽¹⁾

ref T a = ref (i == 0 ? ref b : ref c);

...но и крайне чудесное:

// assignment of l-value⁽²⁾ conditioned by C#7 'ref-locals'

(i == 0 ? ref b : ref c) = a;

эта строка кода присваивает значение a или b или c в зависимости от значения i.



Примечания
1. r-значение - это право - ручная сторона назначения, значение, которое присваивается.
2. l-значение - это левый-ручная сторона присваивания, переменная, которая получает назначенное значение.

Comments

    Ничего не найдено.