「If文」の版間の差分
削除された内容 追加された内容
出典を追加。不正確な記述を排除。 |
→Common Lisp での例: condでの書き換えについては冗長なので削除しました。 タグ: 2017年版ソースエディター |
||
(他の1人の利用者による、間の6版が非表示) | |||
1行目:
{{複数の問題
|出典の明記=2024-
|独自研究=2024-
}}
{{小文字}}
9行目:
具体的な構文はプログラミング言語によって異なるが一般的に、条件式と、条件式の評価結果の値が「真として扱うべき値」の場合に実行される「then節」と呼ばれる部分があり、「偽として扱うべき値」の場合に実行されるelse節と呼ばれる部分が付く場合もある。「もしAならばX、BならばY、それ以外はZ」というように複数の条件で分岐する場合、[[C言語]]のようにif-else文を入れ子にすることで疑似的にelse-if節をサポートする言語もあれば、真のelse-if節をサポートする言語もある。
then節とelse節が[[式 (プログラミング)|式]]になる「[[条件演算子]]」がある言語も多い。言語によってはifが文ではなく、条件演算子と同様の「if式」である言語もある。
== 真偽値 ==
「真として(あるいは、偽として)扱うべき値」について詳説する。条件式の値が[[真理値]]をとる[[ブーリアン型]]でなければならない言語もあるが、そのように限定していない言語もある。C言語にはそもそもブーリアン型が無く{{code|int|c}}で代用しているが、条件式としては汎整数型のゼロ(0)の他、[[ヌルポインタ]]や[[浮動小数点数]]型の 0.0 なども偽として扱われる。[[Ruby]]ではnilとfalse以外は真として扱われる。[[JavaScript]]にはtruthyとfalsyという用語があり、falseの他いくつかの値がfalsyで、その他の多くの値はtruthyである。比較的少数の偽になる値の他は、真、という言語が多いが、それと逆に、[[Dart]]言語(のproduction mode)のようにtrue以外は偽という言語もある(checked modeではbool以外の型だとエラー)。
== 構文
以下ではいくつかの言語やソフトウェアにおける、if文またはそれに類似したものの
=== C ===
if文の条件式はスカラー型の式である([[構造体]]や[[共用体]]のような[[複合型]]の式は使えない)<ref>[https://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf ISO/IEC 9899:1999 §6.8.4.1 The if statement]</ref>。[[C99]]よりも前の規格では真理値のみを扱うための型は無かったため、従来から{{code|int|c}}型で代用されてきた。整数値0に等しい値(あるいは暗黙変換によって0に等しくなる値)は偽、他の値は真として扱われる。真を代表して表すための値は整数値1である(比較式の結果は{{code|int|c}}型であり、0または1となることが保証されている<ref>[https://ja.cppreference.com/w/c/language/operator_comparison 比較演算子 - cppreference.com (C)]</ref>)。then節とelse節には、1個の文か、<code>{ }</code>で囲まれる複文([[ブロック (プログラミング)|ブロック]])を書く。
真の時だけ実行するとき
30行目:
else
else節
</syntaxhighlight>
<!-- 以下の例では、規格バージョンによらない構文であることを示すため、C99 で標準化された「//」の形式のコメントはあえて使っていない。 -->
複数の条件で分岐するときは以下のように書くことができる。
<syntaxhighlight lang="c">
int x = f();
if (x == 1) {
/* x の値が 1 のとき */
}
else if (x == 2) {
/* x の値が 2 のとき */
}
else {
/* x の値が 1 でもなく 2 でもないとき */
}
</syntaxhighlight>
実際には以下のようにif-elseの入れ子となっているだけである。
<syntaxhighlight lang="c">
int x = f();
if (x == 1) {
/* x の値が 1 のとき */
}
else
if (x == 2) {
/* x の値が 2 のとき */
}
else {
/* x の値が 1 でもなく 2 でもないとき */
}
</syntaxhighlight>
上記のコードは[[switch文]]で書くこともできるが、比較対象が整数定数でない場合や、1つの条件式にAND条件やOR条件を組み合わせる場合はif文を使う必要がある。ただしあまりに多数の条件分岐をif-elseで記述すると、入れ子階層の上限に達してしまい、コンパイル不能となることもある<ref>[https://learn.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1061 Fatal Error C1061 | Microsoft Learn]</ref>。C99の規格で保証されている入れ子階層の数は127までである<ref>[https://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf ISO/IEC 9899:1999 §5.2.4.1 Translation limits]</ref>。多数のcaseラベルを含むswitch文はコンパイラによって[[テーブルジャンプ]]に置き換えられることもあり、その最適化が施された場合は最初のラベルに該当するケースと最後のラベルに該当するケースでパフォーマンスに差はない。一方、if文における最後の分岐に該当する場合、それ以前の分岐における条件式をすべて実行することになり、分岐の数に応じてパフォーマンスが悪化する。
Cでは代入は文ではなく式であり値を返すため、以下のように条件式として代入式を使うこともできる。
<syntaxhighlight lang="c">
int x;
if (x = f()) {
/* x の値が 0 でないとき */
}
else {
/* x の値が 0 のとき */
}
</syntaxhighlight>
しかし不注意なプログラマは比較演算子の<code>==</code>と間違えて<code>=</code>と記述してしまうこともあるため、このような書き方をすると警告を出す仕様になっているコンパイラも多い<ref>[https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4706 Compiler Warning (level 4) C4706 | Microsoft Learn]</ref><ref>[https://clang.llvm.org/docs/DiagnosticsReference.html#wparentheses Diagnostic flags in Clang — Clang git documentation]</ref>。
=== C++ ===
[[C++]]はCから発展した言語であり、構文なども概ね上位互換だが、細かな仕様において互換性のない部分も多い。
値として{{code|false|cpp}} (0) または{{code|true|cpp}} (1) のみを取りうる{{code|bool|cpp}}型を持っており、組み込みの型に対する比較式の結果は{{code|bool|cpp}}型となる<ref>[https://ja.cppreference.com/w/cpp/language/operator_comparison 比較演算子 - cppreference.com (C++)]</ref>。if文の条件式はこの{{code|bool|cpp}}型に暗黙的に変換可能な式を受け付ける。Cとの互換性のため、{{code|bool|cpp}}型は整数型の一種であり、その他の整数型や浮動小数点数型、ポインタ型などの値は、条件式の文脈において{{code|bool|cpp}}型に暗黙変換可能となっている。そのため、このような型<code>T</code>への暗黙変換演算子オーバーロード{{code|operator T()|cpp}}を持つユーザー定義型のインスタンスであれば、if文の条件式として直接使うことも可能である。
<syntaxhighlight lang="c++">
struct MyStruct {
std::string name;
operator size_t() const { return name.size(); }
};
MyStruct obj = {"abc"};
if (obj) {
// obj.name が空文字列でないとき。
}
size_t size = obj; // 暗黙の型変換があらゆる場面で発動する。
</syntaxhighlight>
ただしこのような暗黙変換は思わぬ場面で発動することもあり、問題を引き起こすことが多い。安全のため、[[C++11]]では、明示的な型変換演算子オーバーロードを定義できる{{code|explicit operator T()|cpp}}の構文がサポートされた<ref>[https://cpprefjp.github.io/lang/cpp11/explicit_conversion_operator.html 明示的な型変換演算子のオーバーロード - cpprefjp C++日本語リファレンス]</ref>。<code>T</code>が{{code|bool|cpp}}の場合、条件式の文脈においては暗黙変換可能となる。
<syntaxhighlight lang="c++">
struct MyStruct {
std::string name;
explicit operator bool() const { return !name.empty(); }
};
MyStruct obj = {"abc"};
if (obj) {
// obj.name が空文字列でないとき。
}
bool b = static_cast<bool>(obj); // 条件式の文脈でない場合、型変換には明示的なキャストが必要。
</syntaxhighlight>
C++ではif文の条件式で変数を宣言することも可能である。変数の生存期間はそのif-else文を抜けるまでとなる。
<syntaxhighlight lang="c++">
if (int x = f()) {
// x の値が 0 でないとき。
}
else {
// x の値が 0 のとき。
}
</syntaxhighlight>
[[C++17]]では、if文における初期化と条件式を分離した構文が使えるようになった<ref>[https://cpprefjp.github.io/lang/cpp17/selection_statements_with_initializer.html if文とswitch文の条件式と初期化を分離 - cpprefjp C++日本語リファレンス]</ref>。
<syntaxhighlight lang="c++">
if (int x = f(); x == 123) {
// x の値が 123 のとき。
}
else {
// x の値が 123 でないとき。
}
</syntaxhighlight>
=== Java ===
[[Java]]のif文は条件式として{{code|boolean|java}}型のみを許可する。{{code|boolean|java}}型の変数への代入または[[プリミティブラッパークラス]]{{Javadoc:SE|name=java.lang.Boolean|java/lang|Boolean}}型の変数への代入を除き、代入式を記述することはできない。
C++のようにif文の条件式の中で変数を宣言することはできないが、Java 16では、{{code|instanceof|java}}演算子を使ったパターンマッチングの構文をサポートするようになった<ref>[https://docs.oracle.com/javase/jp/16/language/pattern-matching-instanceof-operator.html Java言語更新 - instanceofのパターン・マッチング | Java SE 16]</ref>。
<syntaxhighlight lang="java">
Object obj = getSomeObject();
if (obj instanceof String str) {
// obj の型が String のとき。
System.out.println("String length = " + str.length());
}
else {
// obj の型が String でないとき。
}
</syntaxhighlight>
上記は下記と等価である。
<syntaxhighlight lang="java">
Object obj = getSomeObject();
if (obj instanceof String) {
// obj の型が String のとき。
String str = (String) obj;
System.out.println("String length = " + str.length());
}
else {
// obj の型が String でないとき。
}
</syntaxhighlight>
=== C# ===
[[C Sharp|C#]]はJavaとよく似ており、if文は条件式として{{code|bool|cs}}型のみを許可する。{{code|bool|cs}}型の変数への代入または{{code|bool|cs}}への暗黙変換演算子{{code|static implicit operator bool()|cs}}などをユーザー定義した型の変数への代入を除き、代入式を記述することはできない。
C# 7では{{code|is|cs}}演算子が拡張され、型パターンなどの構文が使えるようになった<ref>[https://devblogs.microsoft.com/premier-developer/dissecting-the-pattern-matching-in-c-7/ Dissecting the pattern matching in C# 7 - Developer Support]</ref><ref>[https://atmarkit.itmedia.co.jp/ait/articles/1708/02/news013_2.html 第3回 型による分岐の改良:特集:C# 7の新機能詳説(2/2 ページ) - @IT]</ref>。
<syntaxhighlight lang="cs">
object obj = GetSomeObject();
if (obj is string str) {
// obj の型が string のとき。
System.Console.WriteLine("String length = " + str.Length);
}
else {
// obj の型が string でないとき。
}
// 変数 str は if-else 文を抜けた後も使用できるが、未割り当て(未初期化)となる。
</syntaxhighlight>
127 ⟶ 267行目:
=== BASICの場合 ===
真の時だけ実行するとき
<syntaxhighlight lang="basic">
IF 条件式 THEN 真文
</syntaxhighlight>
真と偽で実行文を変えるとき
<syntaxhighlight lang="basic">
IF 条件式 THEN 真文 ELSE 偽文
</syntaxhighlight>
真文・偽文が1行で書ききれない場合は[[goto文]]が併用される。
=== Visual Basicの場合 ===
[[Visual Basic]] (VB)、[[Visual Basic for Applications]] (VBA)、[[Visual Basic .NET]] (VB.NET) は複文にも対応している。
真の時だけ実行するとき
<syntaxhighlight lang="vb">
151 ⟶ 297行目:
</syntaxhighlight>
真文・偽文が1行だけの場合にはBASICと同様の書き方(単一行構文)も可能である<ref>[https://learn.microsoft.com/en-us/office/vba/language/concepts/getting-started/using-ifthenelse-statements Using If...Then...Else statements (VBA) | Microsoft Learn]</ref><ref>[https://learn.microsoft.com/ja-jp/dotnet/visual-basic/language-reference/statements/if-then-else-statement If...Then...Else ステートメント - Visual Basic | Microsoft Learn]</ref>。
<!--
=== REALbasicの場合 ===
真の時だけ実行するとき
165 ⟶ 311行目:
偽文
End If
--><!-- あまりにマイナーすぎるうえにVBと同じ仕様のようであり、特筆性がない。 -->
=== 表計算ソフトウェア
[[表計算ソフト|表計算ソフトウェア]]の[[Microsoft Excel]]、[[OpenOffice.org]] Calc、[[LibreOffice Calc]]、[[Google スプレッドシート]]などでは、ワークシート関数のひとつとして<code>IF</code>関数をサポートしている。
IF(テストする条件, 真の場合の値, 偽の場合の値)
192 ⟶ 339行目:
IFS(条件式1, 真の場合1, 条件式2, 真の場合2, ..., 条件式127, 真の場合127)
条件式は先に評価されるべきものから並べる必要がある。IF関数の入れ子構造と処理は同一であるが、簡潔に記述できる。<!-- 可読性と簡潔性は別の観点。簡潔に書けるからといって可読性が高いとは限らない。条件の数が増えると読みづらいことには変わりない。 -->
LibreOffice CalcとExcelの<code>IFS</code>関数では、最大127個の条件をテストすることができる。ただし、<code>IF</code>または<code>IFS</code>であまりにも多くの条件をネストすることは推奨されていない。複数の条件は正確な順序で入力する必要があり、かつ、構築、テスト、更新を行うのが大変難しくなる場合があるからである<ref name="office_ifs_function"/>。
230 ⟶ 377行目:
または
条件式 NIF 偽文 ELSE 真文 THEN
=== ひまわりの場合 ===
279 ⟶ 426行目:
(setq nc nb))
</syntaxhighlight>
Common Lispでは文ではなく式であるため、
<syntaxhighlight lang="lisp">
(setq nc (if (> na nb) na nb))
327 ⟶ 469行目:
If (左辺) { 右辺 }
と等価とみなすことができる。つまり左辺が条件文で、右辺が真文となるわけである。
同様に <code>||</code> を論理和を表す演算子だとすると、
338 ⟶ 481行目:
と等価となり、左辺が偽のときだけ右辺が実行される。
たとえば[[MS-DOS]]や[[Microsoft Windows|Windows]]の[[バッチファイル]]では条件付き処理シンボル<code>&&</code>と<code>||</code>がある<ref>[https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10)#using-multiple-commands-and-conditional-processing-symbols Command shell overview | Microsoft Learn]</ref>。
<syntaxhighlight lang="bat">
CHDIR C:\HOGE || ECHO フォルダがみつかりません </syntaxhighlight> (もしCHDIRコマンドが失敗したら、ECHOコマンドが実行される)
|