コンピュータ プログラミングにおいて、三項条件演算子は、いくつかのプログラミング言語の基本的な条件式の構文の一部である三項演算子です。これは通常、条件演算子、条件式、三項 if、またはインライン if (省略形はiif )と呼ばれます。式または は、の値が true の場合はに評価され、それ以外の場合はに評価されます。これを「if a then b else c」と読み上げることができます。 形式が最も一般的ですが、代替構文も存在します。たとえば、Raku では、中置演算子およびとの混同を避けるために構文が使用されていますが、 Visual Basic .NETでは という形式が代わりに使用されます。
if a then b else ca ? b : cbaca ? b : ca ?? b !! c?!If(a, b, c)
これはもともとCPLに由来しており、そこでは と同等の構文がでした。[1] [2]e1 ? e2 : e3e1 → e2, e3
多くの三項演算子が考えられますが、条件演算子は非常に一般的であり、他の三項演算子は非常にまれであるため、条件演算子は一般に三項演算子と呼ばれます。
バリエーション
三項演算子の詳細な意味と構文は、言語によって大きく異なります。
ある言語と別の言語との間のトップレベルの違いは、式が副作用を許可するかどうか(ほとんどの手続き型言語と同様)、および言語が短絡評価セマンティクス (選択された式のみが評価される) を提供するかどうか (ほとんどの言語のほとんどの標準演算子はすべての引数を評価する) です。
言語が副作用のある式をサポートしていても短絡評価を指定していない場合、どの式が最初に評価されるかについてさらに区別が存在します (言語が特定の順序を保証している場合) (条件も式としてカウントされることに留意してください)。
さらに、順序が保証されていない場合は、結果が不確定 (何らかの順序で取得された値)と未定義(副作用やクラッシュが発生した場合にコンパイラの判断で決まる値) のどちらに分類されるかについて区別が存在します。
言語が式での副作用を許可しない場合 (関数型言語では一般的)、評価の順序には値の意味論がありません。ただし、無限再帰が終了するかどうかに影響したり、その他のパフォーマンスへの影響があったりする可能性があります (一致式を持つ関数型言語では、短絡評価が本質的であり、三項演算子の自然な使用はあまり発生しないため、この点はあまり問題になりません)。
これらの理由により、一部の言語では、ステートメント形式はvariable = condition ? expr1 : expr2;ブロック条件形式とは微妙に異なるセマンティクスを持つことがありますif (condition) { variable = expr1; } else { variable = expr2; }(C 言語 (例の構文) では、これらは実際には同等です)。
ネストされた三項演算子の結合性も言語によって異なる場合があります。ほとんどすべての言語では、三項演算子は右結合であるため、 はa == 1 ? "one" : a == 2 ? "two" : "many"直感的に と評価されますa == 1 ? "one" : (a == 2 ? "two" : "many")が、特にPHP は左結合であることがよくあり、[3]次のように評価されます。これは、プログラマが期待することはほとんどありません。(示されている例では、三項演算子の演算子優先順位(a == 1 ? "one" : a == 2) ? "two" : "many"が低い と想定していますが、これはすべての C ファミリ言語や他の多くの言語で当てはまります。)
マップと同等
三項演算子は、バイナリ マップ演算として見ることもできます。
R やリテラル式タプルを持つ他の言語では、R 式のようなもので三項演算子をシミュレートできます(このイディオムは、0 起点の添え字を持つ言語ではやや自然です)。ネストされた三項演算子は、関数が条件ベクトルの最初の真の値のインデックスを返すようにシミュレートできます。これらのマップ同等物は両方とも二項演算子であり、三項演算子がセマンティクスではなく構文で三項であることがわかることに注意してください。これらの構造は、関数合成ではなくデータ連結に基づく弱い形式のカリー化と見なすことができます。
c(expr1,expr2)[1+condition]c(expr1,expr2,expr3)[which.first((c(cond1,cond2,TRUE))]which.first
言語がfutures または promisesのメカニズムを提供する場合、短絡評価はバイナリ マップ操作のコンテキストでシミュレートできる場合もあります。
条件付き割り当て
もともと ALGOL 60 からの ALGOL の条件付き割り当ては次のとおりです。
変数 := if 条件 then 式1 else 式2;
?:次のように使用されます。
条件 ?真のときの値 :偽のときの値
条件は、ブール式として真または偽として評価されます。ブール条件の評価に基づいて、条件が真の場合は式全体がvalue_if_true を返し、そうでない場合はvalue_if_false を返します。通常、2 つのサブ式value_if_trueとvalue_if_false は同じ型である必要があり、これによって式全体の型が決まります。この型チェックの重要性は、演算子の最も一般的な使用法、つまり条件付き代入文にあります。この使用法では、次のように代入文の右側の式として表示されます。
変数=条件 ?真のときの値 :偽のときの値
?: 演算子は、Scheme、ML、Haskell、XQueryなどの関数型プログラミング言語での条件式 ( if-then-else構造) の動作に似ています。これは、これらの言語では if-then-else がステートメントではなく式を形成するためです。
使用法
条件演算子の最も一般的な使用法は、簡潔で単純な条件付き代入文を作成することです。たとえば、日曜日の店舗の通常の営業時間を9時から12時に変更するCコードを実装する場合、次のように使用できます。
int開店時間= ( day ==日曜日) ? 12 : 9 ;
より冗長な
int開始時間;
もしday == SUNDAYなら、opening_timeは12です。そうでなければ、opening_timeは9です。
2 つの形式はほぼ同等です。 は?:式であり、if-then-elseはステートメントであることに留意してください。条件演算子からtrue部分もfalse部分も省略すると、解析時にエラーが報告されることに注意してください。これは、 else 節を省略できる if-then-else ステートメントとは対照的です。
関数型プログラミングを重視する言語のほとんどは、そもそも通常の条件式が式であるため、このような演算子は必要ありません。たとえば、Scheme式は意味的に C 式 と同等です。これは、 と記述できるALGOLや、Smalltalk ( ) やRuby ( 、ただしこれも機能します)などの多くの命令型言語にも当てはまります。
(if (> a b) a b)(a > b) ? a : bresult := if a > b then a else bresult := (a > b) ifTrue: [ a ] ifFalse: [ b ]result = if a > b then a else b endresult = a > b ? a : b
言語によっては、どちらか一方のみが変数に割り当てられる場合でも、真偽式の両方を評価する場合があることに注意してください。つまり、真偽式または偽偽式に関数呼び出しが含まれている場合、その結果が使用されるかどうかに関係なく、その関数が呼び出されて実行される可能性があります (関数の実行による関連する副作用が発生します)。プログラマーは、プログラミング言語の仕様を参照するか、三項演算子をテストして、言語が両方の式をこのように評価するかどうかを判別する必要があります。評価される場合、これが望ましい動作ではない場合は、if-then-else ステートメントを使用する必要があります。
アクションスクリプト3
条件?真のときの値:偽のときの値
エイダ
Ada 2012 版では、量化式や式関数を含む拡張された式セットの一部として、条件式 (ifおよびを使用) が導入されました。Ada 2012 の根拠[4]には、Ada にこれまで条件式がなかった理由と、新たに追加された「契約」(これも新しい) をサポートするためなどの理由が述べられています。
case
Pay_per_Hour := ( Day = Sundayの場合 は12.50 、それ以外の場合は10.00 );
if_expressionの値自体がブール型の場合、 のelse部分は省略でき、値は True になります。 を使用して複数の条件を連鎖させることができますelsif。
アルゴル60
ALGOL 60 では、命令型プログラミング言語に 条件式(つまり三項条件) が導入されました。
if <ブール式> then <式> else <式>
条件文ではなく:
整数開始時間;
day = Sundayの場合、opening_time := 12 ;そうでない場合、opening_time := 9 ;
プログラマーは条件式を使用して、より簡潔に記述できます。
整数開始時間;
オープニングタイム:= day = Sundayの場合は12 、それ以外の場合は9 ;
アルゴル68
ALGOL 68の両方の選択句( if句とcase句) では、コーダーに「太字」構文または「簡潔」形式のどちらかの選択肢が提供されます。
- 単一のif選択句:
if条件then文 [ else文 ] fi
- 「簡単な」フォーム:
( condition | statements | statements )
- 「簡単な」フォーム:
- 連鎖されたif choice 句:
if条件1 then文elif条件2 then文 [ else文 ] fi
- 「簡単な」フォーム:
( condition1 | statements |: condition2 | statements | statements )
- 「簡単な」フォーム:
オーストラリア
次の構文では、両方の式が評価されます (value_if_false最初に が評価され、condition次に が評価されますvalue_if_false)。
結果←真のときの値⊣ ⍣条件⊢偽のときの値
この代替構文は短絡評価を提供します:
結果← {条件:真のときの式⋄偽のときの式} ⍬
AWK
結果 = 条件 ? 真のときの値 : 偽のときの値
バッシュ
真の三項演算子は算術式にのみ存在します。
((結果=条件?真のときの値:偽のときの値))
文字列の場合、次のような回避策のみが存在します。
結果= $( [[ " $a " = " $b " ]] && echo "value_if_true" || echo "value_if_false" )
は、評価できる"$a" = "$b"任意の条件[[ … ]]構造にすることができます。 の代わりに、[[ … ]]他の任意の bash コマンドにすることができます。 正常に終了すると、最初の echo コマンドが実行され、それ以外の場合は 2 番目の echo コマンドが実行されます。
C
C言語の従来の if-else 構造は次のように記述されます。
if ( a > b ) {結果= x ; } else {結果= y ; }
これは次の文のように書き直すことができます。
結果= a > b ? x : y ;
if-else構造と同様に、式「x」と「y」のどちらか一方のみが評価されます。これは、「x」または「y」の評価に副作用がある場合に重要です。[5]条件演算子の結果を左辺値として使用しようとした場合の動作は未定義です。[5]
Cの GNU拡張機能により、2 番目のオペランドを省略し、最初のオペランドを暗黙的に 2 番目のオペランドとして使用することもできます。
a = x ? : y ;
この式は次の式と同等である。
a = x ? x : y ;
ただし、式aとx は1 回だけ評価されます。式の評価に副作用がある場合、この違いは重要です。この省略形は、他の言語ではElvis 演算子と呼ばれることもあります。
C#
C#では、条件が true の場合、最初の式が評価されて結果になります。false の場合、2 番目の式が評価されて結果になります。Java と同様に、2つの式のうち 1 つだけが評価されます。
// 条件 ? first_expression : second_expression;
static double sinc ( double x ) { return x != 0.0 ? Math . Sin ( x ) / x : 1.0 ; }
C++
Cとは異なり、 C++?:の演算子の優先順位は代入演算子(または)と同じであり、左辺値を返すことができます。[6]つまり、やのような式はどちらも有効であり、異なる方法で解析され、前者はと同等になります。
=OP=q ? a : b = c(q ? a : b) = cq ? a : (b = c)
C++では、初期化と代入が明示的に区別されるため、条件付き代入の状況でif-else文を使用できないことがあります。このような場合、関数呼び出しを使用することは常に可能ですが、これは面倒で洗練されていない場合があります。たとえば、フィールドまたは基本クラスのコンストラクタの引数として条件によって異なる値を渡す場合、単純なif-else文を使用することはできません。この場合は、条件付き代入式、つまり関数呼び出しを使用できます。また、一部の型では初期化は許可されていても代入は許可されていないことや、代入演算子とコンストラクタがまったく異なることを行うことにも留意してください。この最後の点は参照型に当てはまります。たとえば、次のようになります。
#include <iostream> #include <fstream> #include <文字列>
int main ( int argc , char * argv []) { std :: string name ; std :: ofstream fout ;
if ( argc > 1 && argv [ 1 ]) { name = argv [ 1 ]; fout . open ( name . c_str (), std :: ios :: out | std :: ios :: app ); }
std :: ostream & sout = name . empty () ? std :: cout : fout ;
sout << "Hello, world! \n " ;
0 を返す; }
この場合、演算子の代わりにif-else?:ステートメントを使用すると、割り当てのターゲットが分岐の外側でポインターとして宣言され、別のオブジェクトに自由に再バインドできるようになります。
std :: ostream * sout = & fout ; if ( name . empty ()) { sout = & std :: cout ; } * sout << "Hello, world! \n " ;
この単純な例では、soutポインターをデフォルト値に初期化できるため、ポインターが初期化されていない状態やnull のままになるリスクが軽減されます。ただし、適切なデフォルト値が存在しない場合や、デフォルト値の作成にコストがかかる場合があります。より一般的に言えば、null 許容ポインターを追跡すると、認知負荷が増加します。したがって、演算子を介した参照への条件付き割り当てによってのみ、述語に基づいて 2 つの選択肢のうちの 1 つからのみ変数を初期化する?:というセマンティクスが適切に伝達されます。
さらに、条件演算子は左辺値、つまり別の値を割り当てることができる値を生成することができます。次の例を考えてみましょう。
#include <iostream>
int main ( int argc , char * argv [])
{
整数a = 0 ;
整数b = 0 ;
( argc > 1 ? a : b ) = 1 ;
std :: cout << "a: " << a
<< " b: " << b
<< '\n' ;
0 を返します。
}
この例では、ブール式が8 行目のargc > 1値を生成する場合、その値は変数 に割り当てられ、それ以外の場合は、その値は変数 に割り当てられます。
true1a1b
CFML
CFML?:の演算子の例:
結果 = randRange ( 0 , 1 ) ? "表" : "裏" ;
およそ 50% の確率で、randRange()式は 1 (true) または 0 (false) を返します。つまり、結果はそれぞれ「表」または「裏」の値になります。
Lucee、Railo、ColdFusion 11固有の
Lucee、Railo、 ColdFusion 11 も Elvis 演算子を実装しており、?:式の値が null でない場合はその値を返し、それ以外の場合は指定されたデフォルトを返します。
構文:
結果 = 式 ? : 式が null の場合の値
例:
結果 = f () ? : "デフォルト" ;
// where...
function f (){
if ( randRange ( 0 , 1 )){ // 0 または 1 (false / true)
return "value" ;
}
}
writeOutput (結果);
この関数は、およそ 50% の確率でf()戻り値を返しますが、それ以外の場合は何も返しません。 「value」を返す場合はその値を取得し、それ以外の場合は「default」の値を取得します。
valuef()result
コーヒースクリプト
CoffeeScriptでこの演算子を使用する例:
1が2の場合は「真の値」、それ以外の場合は「偽の値」
「偽値」を返します。
コモンリスプ
Common Lispでの条件式を使用した割り当て:
( setq結果( if ( > a b ) x y ))
代替形式:
( if ( > a b ) ( setq結果x ) ( setq結果y ))
結晶
Crystalでこの演算子を使用する例:
1 == 2 ? 「真の値」: 「偽の値」
を返します"false value"。
Crystal コンパイラは条件演算子をif式に変換するため、上記は意味的には次のものと同一になります。
1 == 2の場合は「真の値」、それ以外の場合は「偽の値」、終了
ダーツ
Dartプログラミング言語の構文はCファミリーに属し、主に Java、C#、JavaScript などの言語に影響を受けており、条件式の従来の構文を継承しています。
?:
例:
x .isEven ? x ~/ 2 : x * 3 + 1を返します。
Dart の他の条件と同様に、 の前の式はブール?値に評価される必要があります。
Dart 構文では、?との両方を:さまざまな方法で使用しているため、言語の文法に曖昧さが生じます。次のような式:
{ x をTとする? [ 1 ] : [ 2 ] }
2 つのリストのいずれかを含む「セット リテラル」または「マップ リテラル」として解析できます{((x as T?)[1]) : [2]}。このような状況では、言語は常に条件式を選択します。
Dart には 2 番目の三項演算子もあります。この[]=演算子はリストやマップ内の値を設定するためによく使用されますが、Dart のコンテキストでは「三項演算子」という用語はあいまいになります。
デルファイ
Delphiでは、関数を使用しIfThenて と同じことを実現できます?:。System.Mathライブラリが使用されている場合、関数はInteger、Double、ExtendedIfThenなどの数値を返します。 ライブラリが使用されている場合、この関数は文字列値を返すこともできます。
System.StrUtils
使用System.Math
function IfThen ( AValue : Boolean ; const ATrue : Integer ; const AFalse : Integer ) : Integer ; function IfThen ( AValue : Boolean ; const ATrue : Int64 ; const AFalse : Int64 ) : Int64 ; function IfThen ( AValue : Boolean ; const ATrue : UInt64 ; const AFalse : UInt64 ) : UInt64 ; function IfThen ( AValue : Boolean ; const ATrue : Single ; const AFalse : Single ) : Single ; function IfThen ( AValue : Boolean ; const ATrue : Double ; const AFalse : Double ) : Double ;関数IfThen ( AValue : Boolean ; const ATrue : Extended ; const AFalse : Extended ) : Extended ;
System.StrUtils図書館
の利用
関数IfThen ( AValue : Boolean ; const ATrue :文字列; AFalse :文字列= '' ) :文字列;
使用例:
function GetOpeningTime ( Weekday : Integer ) : Integer ; begin { この関数は、指定された曜日の開店時間を返します。日曜日の場合は 12、その他の曜日の場合は 9 } Result := IfThen (( Weekday = 1 )または( Weekday = 7 ) , 12 , 9 ) ; end ;
ただし、真の三項演算子とは異なり、比較を実行する前に両方の結果が評価されます。たとえば、結果の 1 つがデータベース テーブルに行を挿入する関数の呼び出しである場合、その特定の結果を返す条件が満たされているかどうかに関係なく、その関数が呼び出されます。
エッフェル
1986 年のオリジナルの Eiffel 純粋 OO 言語には条件式がありませんでした。関数型のスタイルと利点をエージェントの形で統合する Eiffel の拡張機能(関数型ラムダと密接に関連) が 2014 年に提案され、実装されました。
if <ブール式> then <式> else <式>
開始時間:整数
開始時間:=曜日が日曜日の場合は12 、それ以外の場合は9
ファ#
F#では、if-then-else の組み込み構文は、常に値を返す必要がある式になっています。
num =とすると、 x = 10の場合は42、そうでない場合は24 になります。
F# には、戻り値が unit 型の場合に else ブランチを省略できる特別なケースがあります。この方法では、else ブランチを使用せずに副作用を実行できます。
x = 10の場合、printfn "10 です"
しかし、この場合でも、if 式は unit を返します。else ではコンパイラが unit 型であると想定するため、else ブランチを記述する必要はありません。
フォース
FORTH はスタック指向の言語であり、任意の式がスタックに値を残すことができるため、すべての //IFシーケンスは値を生成できます。
ELSETHEN
:テスト( n -- n ) 1 AND IF 22 ELSE 42 THEN ;
このワードはスタック上に 1 つのパラメータを取り、その数が奇数の場合は 22 が残ります。偶数の場合は 42 がスタック上に残ります。
フォートラン
1995 年のリリースでコードが追加されたことにより、三項演算子がFortranコンパイラに組み込み関数として追加されましたmerge。
変数=マージ( x , y , a > b )
関数からどちらかの結果が返される前に、x と y の両方が評価されることに注意してください。ここでは、条件が満たされている場合は x が返され、そうでない場合は y が返されます。
フリーマーカー
このビルトインはFreeMarker 2.3.20 以降に存在します。
のように使用され、C 系言語の三項演算子と同じ役割を果たします。
booleanExp?then(whenTrue, whenFalse)
<#割り当て x = 10>
<#y = 20 を割り当てます>
<#-- x と y の最大値を表示します: -->
${(x > y)?then(x, y)}
行く
Goには三項if文がないので、常に完全なif文を使う必要がある。[7]
ハスケル
組み込みのif-then-else構文はインラインです。式
述語の場合、expr1、それ以外の場合、expr2
タイプがある
ブール-> a -> a -> a
基本ライブラリは次の関数も提供しますData.Bool.bool:
ブール値:: a -> a ->ブール値-> a
どちらの場合も、Haskell はデフォルトで非厳密であるため、選択された式のみが評価されるように特別な処理は必要ありません。これは、演算子と組み合わせて使用すると$、ほとんどの言語とまったく同じように機能する演算子を定義できることも意味します?:。
( ? ) :: Bool -> a -> a -> a ( ? ) pred x y = if pred then x else y挿入句1 ?
-- 例 (vehicle は「飛行機」と評価されます):
arg = 'A'車両= arg == 'B' ? "ボート" $ arg == 'A' ? "飛行機" $ arg == 'T' ? "電車" $ "車"
しかし、パターンガードを使用する方が慣用的である。
-- 例 (vehicle は「飛行機」と評価されます):
arg = 'A'車両| arg == 'B' = "ボート" | arg == 'A' = "飛行機" | arg == 'T' = "電車" |それ以外の場合= "車"
ジャワ
Javaでは、この式は次のように評価されます。
// foo が選択されている場合は、選択された foo を bar に割り当てます。選択されていない場合は、baz を bar に割り当てます
。Object bar = foo .isSelected ( ) ? foo : baz ;
JavaはC#と同様に、使用された式のみを評価し、未使用の式は評価しないことに注意してください。[8]
ジュリア
Juliaでは、「?と の周りのスペースは:必須であることに注意してください。 のような式は有効な三項式ではありません(ただし、と のa?b:c後の改行は許容されます)」[9]?:
JavaScript
JavaScriptの条件演算子は、中間の式をカンマ式にすることができない点を除けば、C++やJavaの条件演算子と似ています。また、C++と同様ですが、 CやPerlとは異なり、右側の代入よりも強く結合することはありません。つまり、 の代わりq ? a : b = cに と同等です。 [10]q ? a : (b = c)(q ? a : b) = c
var timeout = settings === null ? 1000 : settings.timeout ;
C# や Java と同様に、式は、指定された条件に一致する場合にのみ評価され、他の式は評価されません。
リスプ
最初の関数型プログラミング言語であるLispには、文が存在せず、条件文も存在しないため、当然条件式があります。形式は次のとおりです。
( ifテスト式then 式else 式)
したがって:
(日=日曜日12 9の場合)
コトリン
Kotlinには従来の三項演算子は含まれていません?:が、if代入可能な式として使用することができ、[11]if同じ結果を得ることができます。条件文の複雑さが増すにつれて、プログラマーは-else式をa式に置き換えることを検討する場合があることに注意してくださいwhen。
val max = if ( a > b ) a else b
ルア
andLua には従来の条件演算子はありません。ただし、 and演算子の短絡動作によりor、この動作をエミュレートできます。
-- var = cond ? a : b; と同等
var = cond and a or b
aが論理的に偽 (つまりfalseまたは) でない限り、これは成功します。nilこの場合、式は常に になりますb。これを無視すると、予期しない動作が発生する可能性があります。
他にも使用できるバリエーションはありますが、一般的にはより冗長になります。
-- テーブルリテラルを囲む括弧が必要です
var = (
{
[ true ] = a ,
[ false ] = b
}
)[ not not cond ]
Lua の方言である Luau には、if 文に似た三項式がありますが、if 文とは異なり、キーワードがなくend、else節が必要です。オプションでelseif節を追加することもできます。これはイディオムを置き換えるように設計されており、すべてのケースで適切に機能することが期待されています。[12]cond and a or b
-- Luau では
var = if cond then a else b
-- elseif 節の
符号付き = if var < 0 then - 1 elseif var == 0 then 0 else 1
オブジェクティブC
条件? 真のときの値: 偽のときの値
整数最小値= ( 1 < 2 ) ? 1 : 2 ;
条件が であるため、変数はminに設定されます。
1(1 < 2)true
パスカル
Pascal は、ALGOL 60 の簡略化と拡張の両方を実現したものです (主にユーザー定義型の処理用)。簡略化の 1 つは、条件式を削除することでした。これは、同じことが、より簡潔でない条件文形式でも実現できるためです。
パール
Perlの従来の if-else 構造は次のように記述されます。
$a > $bの場合{ $ result = $x ; }そうでない場合{ $result = $y ; }
条件演算子を使用するように書き直しました:
$結果= $a > $b ? $x : $y ;
Perlの条件演算子の優先順位はCと同じですが、C++とは異なります。これは、コンマ演算子よりも優先順位が高いという利点がありますが、三項演算子内の式で使用されるほとんどの演算子の優先順位よりも低いため、括弧を使用する必要はほとんどありません。[13]
Perlの結合性はCやC++と一致しますが、PHPの結合性には一致しません。Cとは異なり、C++と同様に、Perlでは条件式をL値として使用できます。[14]たとえば、次のようになります。
$a > $b ? $x : $y = $result ;
論理式のブール値の結果に応じて、
またはの$resultいずれかに割り当てられます。$x$y
使用される演算子のそれぞれの優先順位規則と結合性により、括弧のないバージョンは明示的に括弧で囲まれたバージョンと同等であることが保証されます。
(( $a > $b ) ? $x : $y ) = $result ;
これは if-else バージョンと同等です。
$a > $bの場合{ $ x = $result ; }そうでない場合{ $y = $result ; }
PHP の
簡単なPHP実装は次のとおりです。
$abs = $value >= 0 ? $value : - $value ;
他のほとんどのプログラミング言語とは異なり、 PHPの条件演算子は右結合ではなく左結合です。したがって、 argにTの値が与えられた場合、次の例のPHPコードは予想どおりtrainではなくhorseという値を生成します。[15]
<?php
$arg = "T" ;
$vehicle = ( ( $arg == 'B' ) ? 'バス' :
( $arg == 'A' ) ? '飛行機' :
( $arg == 'T' ) ? '電車' :
( $arg == 'C' ) ? '車' :
( $arg == 'H' ) ? '馬' :
'フィート' );
echo $vehicle ;
その理由は、2つの条件演算子をネストすると、最後の2つのオプションを分岐とする大きすぎる条件が生成されるためc1 ? o1 : c2 ? o2 : o3です((c1 ? o1 : c2) ? o2 : o3)。これは認識されており[16]、おそらく変更されません。[17]これを回避するには、次の例のようにネストされた括弧が必要です。
<?php
$arg = "T" ;
$vehicle = $arg == "B" ? "バス" :
( $arg == "A" ? "飛行機" :
( $arg == "T" ? "電車" :
( $arg == "C" ? "車" :
( $arg == "H" ? "馬" :
"フィート" ))));
echo $vehicle ;
これにより、右結合条件演算子と同様に、 trainの結果が出力に印刷されます。
パワーシェル
Powershell 7より前のバージョンでは三項演算子はサポートされていません[18]が、条件付き構文では単一行の代入がサポートされています。
$result = if $a -eq $b { "真でした" } else { "偽でした" }
Powershell 7以降では従来の三項演算子がサポートされており、C#の構文に従います。[19]
$result = $a -eq $b ? "は真でした" : "は偽でした"
パイソン
構文上の意見の相違により数年遅れていましたが、 Pythonの条件式演算子はPython拡張提案308として承認され、2006年9月の2.5リリースに追加されました。Pythonの条件演算子は?:、オペランドの順序が一般的な演算子と異なります。一般的な形式は次のとおりです。 [20]
結果 = x if a > b else y
この形式は、x通常の値として、またy例外的なケースとして考慮されるよう促します。
Python 2.5 より前では、条件演算子を近似する方法がいくつかありました (たとえば、2 つの要素の配列にインデックスを付けるなど)。これらはすべて、組み込み演算子と比較すると欠点があります。
R
R ( Sの実装)の従来の if-else 構造は次のとおりです。
もしa < bであれば{ x <- "true" }そうでなければ{ x <- "false" }
各ブロックに文が 1 つしかない場合は、Cのように中括弧を省略できます。
if ( a < b ) x <- "true" else x <- "false"
上記のコードは、次のような非標準の簡潔な方法で記述できます。
x <- if ( a < b ) "true" else "false"
ifelse上記の式を次のように書き直すことができる
関数も存在します。
x <- ifelse ( a < b 、"true" 、"false" )
関数ifelseは自動的にベクトル化されます。例:
> ifelse ( c ( 0 , 2 ) < 1 , "真" , "偽" ) [1] "真" "偽"
楽
楽では、?? 1つの記号の代わりに2つの記号を使用し?
、[21]!!の代わりに2つの記号を使用します。:
$結果= $a > $b ?? $x !! $y ;
ルビー
Rubyでこの演算子を使用する例:
1 == 2 ? 「真の値」: 「偽の値」
「偽値」を返します。
Rubyの伝統的なif-else構文は次のように記述されます: [22]
a > b の場合、結果= x 、そうでない場合、結果= y終了
これは次のように書くこともできます:
結果= if a > b x else y終了
これらは次の文のように書き直すことができます。
結果= a > b ? x : y
さび
Rustは式指向プログラミング言語であるため、既存の構文は従来の三項演算子と同じように動作します。以前のバージョンの言語には演算子がありましたが、との重複のため削除されました[23]。[24]if expr1 else expr2?:?:if
ifより宣言的な...ブロックと比較して、以下のコードにはセミコロンがないことelse、および への割り当ての最後にセミコロンがあることに注意してくださいy。
x = 5とします。
x == 5 { 10 }の場合y = 、そうでない場合は{ 15 }とします。
これは次のように書くこともできます:
x == 5 { 10 }の場合y = 、そうでない場合は{ 15 }とします。
Rust の条件式では中括弧が必須であることに注意してください。
次のような表現も使えますmatch:
y = match x { 5 => 10 , _ => 15 , }とします。
スキーム
Common Lisp と同じです。すべての式には値があります。したがって、組み込み関数をif使用できます。
( let* (( x 5 ) ( y ( if ( = x 5 ) 10 15 ))) ... )
雑談
すべての式(メッセージ送信)には値があります。次のようにifTrue:ifFalse:使用できます。
|x y|
x := 5. y := ( x == 5 ) ifTrue: [ 10 ] ifFalse: [ 15 ] 。
構文
SQLCASE式は三項演算子の一般化です。1 つの条件と 2 つの結果の代わりに、n個の条件とn+1 個の結果を指定できます。
条件が 1 つある場合、これは三項演算子と同等です (ただし、より冗長になります)。
SELECT ( CASE WHEN a > b THEN x ELSE y END ) AS CONDITIONAL_EXAMPLE FROM tab ;
これはいくつかの条件に拡張できます:
SELECT ( CASE WHEN a > b THEN x WHEN a < b THEN y ELSE z END ) AS CONDITIONAL_EXAMPLE FROM tab ;
マイグレーション
標準の式に加えてCASE、MySQL はIF拡張機能として関数を提供します。
IF (条件、a 、b );
SQL サーバー
標準CASE式に加えて、SQL Server (2012 以降) は次のIIF関数を提供します。
IIF (条件、真の値、偽の値)
オラクルSQL
標準式に加えてCASE、Oracle には、switch 文と同様に動作し、等価性をテストするときに条件演算子をエミュレートするために使用できる
可変長関数の対応物があります。
-- 一般的な構文は、ケースと結果のペアを取り、式と比較し、その後にフォールバック結果が続きます:
DECODE (式、ケース1 、結果1 、...ケースN 、結果N 、結果Else )
-- 1 つのケースを選択するだけで条件演算子をエミュレートできます:
DECODE (式、条件、true 、false )
このDECODE関数は現在、標準式に置き換えられ、非推奨となっていますCASE。これは Oracle SQL クエリとPL/SQLブロックの両方で使用できますが、 はdecode前者でのみ使用できます。
迅速
Swift の三項条件演算子は、 Cの伝統的な方法で記述され、式内で使用されます。
結果 = a > b ? a : bとします
Tcl
Tclでは、この演算子はexpr式
でのみ使用できます。
x を5 に設定y を設定[式{ $x == 5 ? 10 : 15 }]
の外部でもexpr、if同様の目的で使用でき、値を返します。
パッケージには数学が 必要です
x を5 に設定y を設定[if { $x == 5 } { :: math :: random $x } else { :: math :: fibonacci $x }]
テストスタンド
National Instruments TestStand 式では、条件が true の場合、最初の式が評価され、条件演算の出力になります。false の場合、2 番目の式が評価され、結果になります。2 つの式のうち 1 つだけが評価されます。
条件?最初の式: 2 番目の式
例えば:
RunState.Root.Parameters.TestSocket.Index == 3 ? Locals.UUTIndex = 3 : Locals.UUTIndex = 0
UUTIndex3 の場合はローカル変数を 3 に設定しTestSocket.Index、それ以外の場合はUUTIndex0 に設定します。
他の言語と同様に、first_expressionとsecond_expression は自律的な式である必要はなく、演算子を変数の割り当てに使用できます。
ローカル.UUTIndex = ( RunState .Root .Parameters .TestSocket .Index == 3 ? 3 : 0 )
ベリログ
Verilogは技術的にはハードウェア記述言語であり、プログラミング言語ではありませんが、両者のセマンティクスは非常に似ています。?:三項演算子の構文を使用します。
// ブロッキング代入を使用する
wire out ; assignment out = sel ? a : b ;
これは、より冗長な Verilog コードと同等です。
// ブロッキング代入を使用する
wire out ; if ( sel === 1 ) // sel は 1 であり、0、x、z のいずれでもない。assign out = a ; else if ( sel === 0 ) // selは 0、x、z (上記で 1 がチェックされている) 。assign out = b ; else // sel は x または z (上記で 0 と 1 がチェックされている)。assign out = [ comment ] ; // a と b はビットごとに比較され、各ビットに対して返される。//ビットが異なる場合は x が、同じ場合はビット値。
ビジュアルベーシック
Visual Basic では?:、それ自体は使用されませんが、この短縮if...elseステートメントの非常によく似た実装があります。この記事で提供された最初の例を使用すると、次の操作を実行できます。
' 変数 = IIf(条件、値が真の場合、値が偽の場合)
Dim開始時間As Integer = IIf ((日= SUNDAY ), 12 , 9 )
上記の例では、IIfは三項関数ですが、三項演算子ではありません。関数として、関数呼び出しが発生する前に、3 つの部分すべての値が評価されます。これにより制限が課せられ、Visual Studio 2008 でリリースされた Visual Basic .Net 9.0 では、Ifの代わりにキーワードを使用する実際の条件演算子が導入されましたIIf。これにより、次のサンプル コードが機能します。
Dim name As String = If ( person Is Nothing , "" , person . Name )
を使用するとIIf、 person が(Nothing)person.Nameであっても が評価され、例外 が発生します。真の短絡条件演算子を使用すると、person が でない限り は評価されません。
nullperson.Namenull
Visual BasicIf()バージョン 9 では、以前から存在していた関数に加えて演算子が追加されましたIIf()。真の演算子であるため、関数の副作用や潜在的な非効率性はありませんIIf()。
トークンの構文は、If([condition], op1, op2)vs と似ていますIIf(condition, op1, op2)。前述のように、関数呼び出しには大きな欠点があります。これは、Visual Basic の関数呼び出しの評価戦略に従ってサブ式をすべて評価する必要があり、結果は常にバリアント型 (VB) またはオブジェクト型 (VB.NET) になるためです。If()ただし、演算子は条件付き評価をサポートし、オペランドの型に基づいて式の型を決定するため、これらの問題に悩まされることはありません。
ジグ
Zigは三項条件演算子の代わりにif-else式を使用する: [25]
const結果= if ( a != b ) 47 else 3089 ;
結果タイプ
明らかに、演算子の結果の型は、?:ある意味では、その 2 番目と 3 番目のオペランドの型の型統合でなければなりません。C では、数値型については算術昇格によってこれが実現されます。C にはポインタ型の型階層がないため、ポインタオペランドは同じ型 (型修飾子を無視) であるか、一方がvoidまたはNULLである場合にのみ使用できます。ポインタ型と整数型または互換性のないポインタ型を混在させると、
未定義の動作になります。
number = spell_out_numbers ? "42" : 42 ;
ほとんどのコンパイラではコンパイル時エラーが発生します。
?: スタイルガイドライン
条件演算子は広く使用されており、余分な言葉が長すぎる場合や構文コンテキストでステートメントが許可されていない場合など、特定の状況でステートメントの使用を回避するのに役立ちますif。例:
#define MAX(a, b) (((a)>(b)) ? (a) : (b))
または
for ( i = 0 ; i < MAX_PATTERNS ; i ++ ) c_patterns [ i ] .ShowWindow ( m_data.fOn [ i ] ? SW_SHOW : SW_HIDE ) ;
(後者の例では、Microsoft Foundation Classes Framework for Win32を使用しています。)
初期化
条件演算子の重要な用途は、複数の初期化ステートメントではなく、単一の初期化ステートメントを許可することです。多くの場合、これにより単一の割り当てが可能になり、識別子を定数にすることもできます。
最も単純な利点は、Python のように変数名の重複を回避できることです。
x = 'foo' 、 b の場合、 それ以外は'bar'
の代わりに:
b の場合:
x = 'foo'
、それ以外の場合:
x = 'bar'
さらに重要なのは、 C++ などのブロック スコープを持つ言語では、if/else ステートメントのブロックによって新しいスコープが作成されるため、次のように、変数を if/else ステートメントの前に宣言する必要があることです。
std :: string s ; if ( b ) s = "foo" ; else s = "bar" ;
条件演算子を使用すると、これが簡素化されます。
std :: string s = b ? "foo" : "bar" ;
さらに、初期化は個別のステートメントではなく宣言の一部になったため、識別子は定数 (正式には、const型の定数) にすることができます。
const std :: string s = b ? "foo" : "bar" ;
ケースセレクター
適切にフォーマットすると、条件演算子を使用して、シンプルで一貫性のあるケース セレクターを記述できます。例:
乗り物= arg == 'B' ?バス: arg == 'A' ?飛行機: arg == 'T' ?電車: arg == 'C' ?車: arg == 'H' ?馬:フィート;
変数割り当てコンテキストで条件演算子を適切に使用すると、割り当てられた変数が複数回ではなく 1 回だけ指定されるため、誤った割り当てによるバグの可能性が減ります。
条件演算子のないプログラミング言語
以下は、条件演算子を提供しない有名な汎用プログラミング言語の例です。
- コーヒースクリプト
- Goプログラミング言語[7](サードパーティのライブラリによって提供される[26])
- マテリアライズド
- Pascalですが、Object Pascal / Delphi
IfThenにも同じ機能があります(ただし注意点あり) - Rustの構文
if..elseは式であり、同じ機能を得るために使用できます。[27] - スカラ
- XProfan
- PowerShell(旧バージョン)では、エレガントな回避策として[28]を使用する。
(<value for true>,<value for false>)[!(<condition>)]
参照
参考文献
- ^ Strachey, Christopher (2000). 「プログラミング言語の基本概念」.高階および記号計算. 13 : 11–49. doi :10.1023/A:1010000313106. S2CID 14124601.
- ^ 「5.5 条件式」。BCPLリファレンスマニュアル(PDF) 。1967年。pp. 16–17。 2016年3月16日時点のオリジナル(PDF)からアーカイブ。 2017年3月15日閲覧。
- ^ Wastl, Eric. 「三項演算子の結合性」. phpsadness.com . PHP Sadness . 2017 年9 月 20 日閲覧。
- ^ “Ada 2012 の理論的根拠”. ACAA 。2015 年12 月 10 日に取得。
- ^ ab ISO.IEC 9899:1999 (E) 6.5.15.4
- ^ 「C++ 演算子の優先順位」。en.cppreference.com。セクション:「注記」。
- ^ ab 「Go には ?: 演算子がありますか?」。Go プログラミング言語 FAQ。2012年 8 月 5 日閲覧。
- ^ Java 7 仕様: 15.25 条件演算子 ? :
- ^ 「制御フロー · Julia 言語」。docs.julialang.org 。2020 年 3 月 12 日閲覧。
- ^ 「ECMA-262 エディション 5.1」。Ecma言語仕様。Ecma International。2013年9 月 7 日閲覧。
- ^ 「Kotlin Lang If Expression」. kotlinlang.org . 2021年4月25日閲覧。
- ^ 「構文 § If-then-else 式」。Luau 。2023年 2 月 7 日閲覧。
- ^ Christiansen, Tom ; Wall, Larry ; Foy, Brian D (2012 年 2 月)。「第 2 章 単項演算子と二項演算子: 条件演算子」。プログラミング Perl (第 4 版)。セバストポル、カリフォルニア州: O'Reilly Media。p . 123。ISBN 978-0-596-00492-7。
- ^ Wall, Larry . 「perlop: 条件演算子」Perl プログラミング ドキュメント。2019年1 月 26 日閲覧。
- ^ Eevee (2012-04-09). 「PHP: 悪いデザインのフラクタル」2015年10月4日閲覧。
- ^ 「比較演算子、例 #3: わかりにくい三項演算子の動作」。PHP ウェブサイト。2013 年 4 月 26 日閲覧。
- ^ 「PHP バグ #61915: 三項演算子の結合性が正しくありません」。PHP ウェブサイト。2012 年 5 月 2 日。2013年 4 月 26 日閲覧。
コードを壊さずにこれを修正することはできません。
- ^ 「about_If - 三項演算子構文の使用」。2023年6月7日。
- ^ 「about_Operators - 三項演算子」。2024年9月3日。
- ^ 「Python 言語リファレンス」。
- ^ Wall, Larry . 「Perl6 演算子」。2009 年 3 月 29 日時点のオリジナルよりアーカイブ。2010 年 5 月 18 日閲覧。
- ^ Rubyプログラミング: 条件付き実行
- ^ 「三項演算子の削除 by pwoolcoc · プルリクエスト #1705 · rust-lang/Rust」。GitHub。
- ^ 「三項演算子の削除 · Issue #1698 · rust-lang/Rust」。GitHub。
- ^ 「Zig 言語リファレンス」ziglang.org . 2023 年 8 月 9 日閲覧。
- ^ 「lo パッケージ - github.com/samber/lo - Go パッケージ」。pkg.go.dev。2023年 9 月 30 日閲覧。
- ^ 「If式」。Rustリファレンス。 2015年7月21日閲覧。
- ^ 「PowerShell の三項演算子」。Stack Overflow。2018年 10 月 9 日閲覧。
外部リンク
- Visual Basic の If 演算子の説明
- Python の条件式の説明 (PEP 308)
- Java言語仕様における説明
- PHP言語ドキュメントの説明
