web-dev-qa-db-ja.com

条件付き?:(三項)演算子を使用する利点

標準のif-elseステートメントとは対照的な?:演算子の利点と欠点は何ですか。明らかなものは:

条件付き?:演算子

  • 直接的な値の比較と割り当てを扱う場合のより短くて簡潔な
  • if/else構造ほど柔軟ではないようです

標準のIf/Else

  • より多くの状況(関数呼び出しなど)に適用できます
  • しばしば不必要に長い

読みやすさは、ステートメントによってそれぞれ異なります。最初に?:演算子にさらされてからしばらくして、その動作を正確に消化するのに時間がかかりました。可能な限りそれを使用することをお勧めしますか、私が多くの非プログラマーと仕事をしていることを考えれば、if/elseに固執することをお勧めしますか?

100
KChaloux

基本的に、結果のステートメントが非常に短く、読みやすさを犠牲にすることなくif/else同等のものよりも大幅に簡潔になった場合にのみ使用することをお勧めします。

良い例え:

int result = Check() ? 1 : 0;

悪い例:

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

これは他の回答でほぼカバーされていますが、「それは表現です」では、なぜそれがそんなに役立つのかを説明していません...

C++やC#などの言語では、それらを使用して(メソッド本体内で)ローカルの読み取り専用フィールドを定義できます。これは、従来のif/thenステートメントでは不可能です。これは、読み取り専用フィールドの値をその単一ステートメント内で割り当てる必要があるためです。

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

以下と同じではありません:

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

同様の方法で、他のコードに3次式を埋め込むことができます。ソースコードをよりコンパクトにする(そして場合によっては結果として読みやすくする)だけでなく、生成されたマシンコードをよりコンパクトで効率的にすることもできます。

MoveCar((shiftKeyDown) ? 10 : 1);

...同じメソッドを2回呼び出すよりも少ないコードを生成できます:

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

もちろん、より便利で簡潔な形式です(タイピングが少なく、繰り返しが少なく、if/elseでコードのチャンクを複製する必要がある場合にエラーの可能性を減らすことができます)。このようなクリーンな「共通パターン」の場合:

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

...使い慣れたif/elseの同等のものよりも、読み取り/解析/理解の方が速いので、コードをより速く「グロッキング」するのに役立ちます。

もちろん、それが有用であるからといって、すべての場合にseが最善であることを意味するわけではありません。 ?:を使用して意味が明確な(またはより明確になった)短いコードにのみ使用することをお勧めします-より複雑なコードで使用する場合、または相互に三項演算子をネストする場合コードは恐ろしく読みにくいです。

50
Jason Williams

そうでなければ、多くの重複コードがある場合は、通常、三項演算子を選択します。

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); 
13
Ryan Bright

定義されている場合はリクエストで送信された値、定義されていない場合はデフォルト値に変数を設定する場合、Web開発を行うときに特に役立ちます。

12
wshato

本当にクールな使い方は次のとおりです。

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

条件演算子は、次のような短い条件に最適です。

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());
}

したがって、最終的には、現在の利便性(使用する方が短いですか?)と後の利便性(およびその他)についてです。それは判断の呼び出しです...しかし、他のすべてのコードフォーマットの問題と同様に、唯一の本当のルールは一貫性があり、コードを維持(または評価)しなければならない人に視覚的に丁寧であることです。

(すべてのコードはアイコンパイル済み)

6
iandisme

三項演算子を使用するときに、それがステートメントではなく式であることを認識する1つのこと。

スキームのような関数型言語では、区別は存在しません。

(if(> a b)a b)

条件付き?:演算子「if/else構造ほど柔軟ではないようです」

関数型言語ではそうです。

命令型言語でプログラミングする場合、通常は式(割り当て、条件ステートメントなど)を使用する状況で三項演算子を適用します。

5
Ken Struys

上記の回答は有効であり、読みやすさが重要であることに同意しますが、さらに2つの考慮すべき点があります。

  1. C#6では、式に基づいたメソッドを使用できます。

これにより、三項を使用することが特に簡潔になります。

string GetDrink(DayOfWeek day) 
   => day == DayOfWeek.Friday
      ? "Beer" : "Tea";
  1. 暗黙的な型変換に関しては、動作が異なります。

暗黙的に両方ともTに変換できるタイプT1T2がある場合、以下はnot動作します:

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

(コンパイラが三項式のタイプを判別しようとするため、T1T2の間の変換は行われないためです。)

一方、以下のif/elseバージョンは動作します:

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

T1Tに変換され、T2も変換されるためです

5
la-yumba

Bool値の割り当てが一目で読みやすくなる場合があります。

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

// Without
button.IsEnabled = !someControl.HasError;
5
Tyler Pantuso

Ternary(?:)演算子の使用を、単純な単一行割り当てif/elseロジックに制限することをお勧めします。このパターンに似たもの:

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

簡単に変換できます:

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

If/else if/else、ネストされたif/else、または複数行の評価につながるif/else分岐ロジックを必要とする状況では、三項演算子の使用を避けます。これらの状況で三項演算子を適用すると、コードが判読できず、混乱し、管理不能になる可能性があります。お役に立てれば。

4
HOCA

値を設定していて、それが常に1行のコードであることがわかっている場合、通常は3項(条件付き)演算子を使用します。コードとロジックが将来変更される可能性がある場合は、他のプログラマーにとってより明確なif/elseを使用します。

さらに興味深いのは ??演算子 です。

4
drharris

条件演算子の利点は、演算子であることです。つまり、値を返します。 ifはステートメントであるため、値を返すことはできません。

4
Gabe

?を使用すると、パフォーマンスが向上します。例えばの演算子MS Visual C++。ただし、これは実際にはコンパイラ固有のものです。コンパイラは、場合によっては条件分岐を実際に最適化できます。

2
darklon

私が最もよく使用しているシナリオは、デフォルト値、特にリターンの場合です

return someIndex < maxIndex ? someIndex : maxIndex;

本当にいいと思うのはこれらの場所だけですが、彼らにとってはそうです。

ただし、ブール値を探している場合、これは適切なことのように見える場合があります。

bool hey = whatever < whatever_else ? true : false;

読みやすく、理解しやすいためですが、より明確にするためにその考えは常に投げられるべきです。

bool hey = (whatever < whatever_else);
2
Jimmy Hoffa

同じ条件で複数のブランチが必要な場合は、ifを使用します。

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

条件が異なる複数のブランチが必要な場合、ステートメントカウントがSnowballである場合は、3項を使用する必要があります。

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変数は初期化時にのみバインドできます。

2
Ben Voigt

三項演算子は右辺値に含めることができますが、if-then-elseは含めることができません。一方、if-then-elseはループおよび他のステートメントを実行できますが、三項演算子は(おそらくvoid)右辺値のみを実行できます。

関連するメモでは、&&および||演算子を使用すると、if-then-elseで実装するのが難しいいくつかの実行パターンを使用できます。たとえば、呼び出す関数がいくつかあり、それらのいずれかが失敗した場合にコードの一部を実行したい場合は、&&演算子を使用してうまく実行できます。その演算子を使用せずに実行すると、冗長コード、goto、または追加のフラグ変数が必要になります。

2
supercat