条件演算子

条件演算子（じょうけんえんざんし、英: conditional operator）は、プログラミング言語の演算子で、条件文と同様な意味があるが、文ではなく値を持つ式になる。評価されると、条件式の値により異なる式が評価され、異なる値になる。 なお、C言語やC++など一部のプログラミング言語において、条件演算子とは後述する「? :」(ハテナマークとコロン) の演算子の名称である。 「If 〜 Then 〜 Else 〜」にあたる三項演算子があり、ほぼ唯一の、プログラミング言語において一般的な三項演算子である。また「If 〜 Then 〜 if」にあたる二項演算子もある。 三項演算子は、条件式・真式・偽式の3つのオペランドを結ぶ。二項演算子の場合は、条件式と、真式または偽式のいずれかの、2つのオペランドを結ぶ。 条件文との違いは、 真式・偽式は式（条件文における節のように文を置くことができない） 式であるため値を持つ である。 C言語などには、次の構文の三項の条件演算子がある。 <条件式> ? <真式> : <偽式> 3項を結ぶ必要上、「?」と「:」の2つの記号を使うが、演算子としては1つの演算子である。 <条件式>は真 (true) または偽 (false) の論理値を返す論理式 (ブール型) である（あるいは論理値に暗黙に型変換可能な型を返す）。真式と偽式は同じ型の値を返さなければならない（暗黙に型変換可能なら許されることもある）。 この構文自身も式であるので値をもち、その値は上記<真式>または<偽式>の値のいずれかである。<条件式>が真の場合は<真式>、偽の場合は<偽式>の値となる。 例えば、Java言語では、次のように用いる。 int weight; ... String message = weight <= 100 ? "OK" : "積載量オーバー"; この場合、変数weightの値が100以下であれば変数messageに"OK"という文字列が代入され、それ以外であれば"積載量オーバー"という文字列が代入される。これは通常のif-else文を用いて書いた次の例と同じ意味であり、コンパイルした結果はしばしば同じものとなる。 String message; if (weight <= 100) { message = "OK"; } else { message = "積載量オーバー"; } 条件演算子はこの例のように、条件によって異なる値をある処理（上の例ではmessageへの代入）に適用する、という場合に記述を簡潔にすることができる。 C言語およびC++では、変数宣言時の初期化に条件演算子を用いることで、再代入を許可しないconst修飾された変数を定義することができるようになる。さらにC++においては、if-else文による初期化では必要な、変数宣言時のデフォルトコンストラクタが不要となる。 const std::string message(weight <= 100 ? "OK" : "積載量オーバー"); 条件演算子の結合性（associativity）は、CやJavaやPerlなどでは、a ? b : c ? d : e は a ? b : (c ? d : e) という意味だが、PHPの三項演算子[1]では (a ? b : c) ? d : e なので注意が必要である。 Rubyでは、<条件式> ? <真式> : <偽式>というC と同じ形で条件演算子を使うことができる。しかし、Ruby の場合は if も文ではなく式なので、入れ子や複数行になる場合は、条件演算子ではなくifを使用する方が好まれている。 Pythonにおいては、Cの条件演算子と同じ機能は、構文に関する論争のため長い間実装されなかったが（論理演算子を使ったハックでなんとか似たことができるというのもあった）、PEP 308として承認され、2006年9月の2.5 releaseに追加された。 Python ではこの機能の式を条件式と呼び、構文は、C言語などとは順序が異なっている（新しい演算子ないしキーワードは導入されなかった）。Perlの後置if修飾子のような見た目になった。 <真の場合の値> if <条件式> else <偽の場合の値> Visual Basic（2008より前）、VBAには演算子はないが、同じように使える関数 Iif がある。 Iif(<条件式>, <真式>, <偽式>) ただし条件演算子と違い、真式・偽式いずれも関数の引数なので、条件式の真偽にかかわらず双方とも評価される。条件に合わない側の値は捨てられるので値に影響はないが、真式・偽式に副作用がある（何か出力する、グローバル変数を書き換えるなど）場合は挙動が異なってくる。 Visual Basic 2008以降には、条件演算子と同様の短絡評価をおこなうIf演算子がある。 If(<条件式>, <真式>, <偽式>) 'または If(<式1>, <式2>) 3引数の場合は、if-then-elseと同様の意味である。2引数の場合は、式1がNothingでない場合は式1の値を、式1がNothingの場合は式2の値を返す。 論理演算子の短絡評価を利用して条件演算子のような処理を書くことができる。 短絡評価を持つ論理演算子について、論理積 expr1 AND expr2 は左辺の式 expr1 が偽値（論理演算の文脈で false と等価な値）なら右辺の式 expr2 は評価されない。 同様に、論理和 expr1 OR expr2 は左辺の式 expr1 が真値（論理演算の文脈で true と等価な値）なら右辺の式 expr2 は評価されない。 従って、左辺 expr1 を条件式とし、その結果が真値の場合に評価されるべき式を論理積の右辺の式 expr2 に書け、また同様に左辺の式 expr1 が偽値の場合に評価されるべき式を論理和の右辺の式 expr2 に書ける。 条件演算子ないしif-else式を短絡評価する論理演算子で模倣すると、 (cond AND expr1) OR expr2 と書ける（ただし expr1 の値は偽値にならないとする）。上記の式は、cond が偽値なら expr1 を評価せずにexpr2 を評価し、cond が真値（かつ expr1 も真値）なら expr2 を評価しない。 条件演算子などとの相違点として、論理演算子の評価結果がブーリアン（またはそれに相当する整数型の値）に変換されるプログラミング言語では expr1 および expr2 の値そのものは利用できない。 条件演算子をサポートしない言語であっても、ifが文ではなく式となっている言語では、if式を用いることで同等の機能を実現できる。例えばF#には組み込みの条件演算子はないが、以下のようにif式で代用できる。 printfn "Now %s." (if (System.DateTime.Now.Hour >= 12) then "PM" else "AM") その他、無名関数を応用したものもある。例えばSmalltalkでは関数呼び出しに相当するメッセージ式に無名関数に相当するブロックを渡すことで条件式を実現している。 value := 0 < 1 ifTrue:[ 1 ] ifFalse: [ 2 ]. なお、この#ifTrue:#ifFalse:は分岐専用の構文ではなくメッセージ式の一例に過ぎない。メッセージ式は誰でも追加できるため、標準のライブラリーだけでも下記のような亜種が存在する。 value := 0 < 1 ifTrue:[ 1 ]. value := value ifNil:[ 1 ] ifNotNil[ 2 ]. value := value ifNil:[ 1 ]. value := value ifNotNil:[ :argument | 1 ]. value := value at: 1 ifAbsent:[ 0 ]. 条件演算子: A ? B : C Null合体演算子: A ?? B など (null時のデフォルト値設定) エルビス演算子: A ?: B (false時のデフォルト値設定) Null条件演算子: A?.B など (nullチェックの自動化)