VBAには三項演算子はないが代替のIIf関数がある
VBAにはC#やJavaなどの「三項演算子(条件 ? 値1 : 値2)」は存在しません。ただし、代わりに演算子ではなくIIf関数で似たような書き方を実現しています。
IIf関数はVB6から互換性もあり便利に見える一方で、利用にあたっては注意点があります。そのためか、書籍や参考資料でもあまり取り上げられないことが多いようです。
これは、IIf関数が他の言語の三項演算子とは異なる挙動を示すため、意図しない結果を招く可能性があるからだと考えられます。
C++、Java、Pythonなど他のプログラミング言語を習得している方向けですが、通常の三項演算子のつもりでIIf関数を利用するとバグを引き起こす恐れがあります。
その想定外の動作の詳細は後述しています。
構文
Function IIf(Expression, TruePart, FalsePart)
Expression | Boolean型の結果を返す条件文を指定します。 |
TruePart | Expressionの結果がTrueの場合にIIf関数の戻り値になります。
ただ、条件文の結果に関わらず、TruePartのコードが実行されます。関数やクラスメソッドを設定することも可能ですが、意図しない動作を引き起こす恐れがあります。(後述) |
FalsePart | Expressionの結果がFalseの場合にIIf関数の戻り値になります。
ただ、TruePartと同様で条件文の結果に関わらず、FalsePartのコードが実行されます。関数やクラスメソッドを設定することも可能ですが、意図しない動作を引き起こす恐れがあります。(後述) |
三項演算子(IIf関数)の書き方
以下のコードは通常のIf文と、同じ内容を三項演算子のIIf関数で書いたコードです。
通常のIf文のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
'// 通常のIf文 Sub IfTest() Dim s '// --- 条件に一致 --- If (1 > 0) Then s = "条件に一致" Else s = "条件に不一致" End If Debug.Print s '// --- 条件に不一致 --- If (0 > 1) Then s = "条件に一致" Else s = "条件に不一致" End If Debug.Print s End Sub |
出力結果
条件に一致
条件に不一致
三項演算子(IIf関数)のコード
1 2 3 4 5 6 7 8 9 10 11 12 |
'// 三項演算子(IIf関数)での条件文 Sub IIfTest() Dim s '// --- 条件に一致 --- s = IIf(1 > 0, "条件に一致", "条件に不一致") Debug.Print s '// --- 条件に不一致 --- s = IIf(0 > 1, "条件に一致", "条件に不一致") Debug.Print s End Sub |
出力結果
条件に一致
条件に不一致
IIf関数の注意点(予期しない挙動について)
VBAのIIf関数、他のプログラミング言語の三項演算子とは異なる重要な特性があります。
Microsoftの公式ドキュメントに説明があります。
https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/iif-function
上記ページの注釈に
「IIf では、 truepart または falsepart のいずれか一方だけが返されますが、評価は両方の引数に対して行われます。 このため、予期しない結果が起きることがあります。 たとえば、 falsepart を評価した結果 0 による除算エラーが発生する場合は、 expr が True であってもエラーが発生します。」
とあります。
これを読んで問題があるとすぐに気が付く人はコーディングに慣れている人です。そうでなければ、なかなか問題に気が付かないと思われます。
以下は問題が発生するソースです。
1 2 3 4 5 6 7 8 9 10 |
Function testMethod(a) Debug.Print a testMethod = a End Function Sub IIfCall() Dim s s = IIf(0 > 1, testMethod(0), testMethod(1)) End Sub |
出力結果
0(0 > 1の条件に一致しないため出力してほしくないが出力される)
1
上のコードであれば0 > 1の条件はFalseなので、第三引数の「testMethond(1)」が処理されることを期待します。しかし実際には第二引数の「testMethod(0)」も処理されてしまいます。
条件文の結果に関わらず、第二引数と第三引数が処理されています。この挙動は他のプログラミング言語の三項演算子と異なります。
これは、IIfが関数であるため、関数呼び出し時にすべての引数が評価される仕様によるものです。つまり、条件の結果に関わらず両方の引数が処理されるため、副作用(関数呼び出し、データベースアクセス、ファイル操作など)を持つ処理を引数に渡すと、意図しない動作を引き起こす可能性があります。
IIf関数の利点
注意点が多いIIf関数ですが、適切に使用すれば以下のようなメリットがあります。
- コードの可読性を損なわない範囲での簡潔な記述
- 副作用のない式の評価
- クエリやSQL文での条件分岐
- 単純な値の選択(文字列、数値、定数など)
コードでこれらの利点を説明します。
1. コードの簡潔性
単純な条件分岐であれば、複数行のIf文を1行にまとめることができます。
1 2 3 4 5 6 7 8 9 |
'// If文の場合(4行) If score >= 60 Then result = "合格" Else result = "不合格" End If '// IIf関数の場合(1行) result = IIf(score >= 60, "合格", "不合格") |
2. 式の中で直接使用できる
IIf関数は式の一部として使用できるため、他の計算や関数呼び出しと組み合わせやすくなります。
1 2 3 4 5 |
'// 計算式の中で条件分岐 total = price * IIf(isMember, 0.9, 1.0) '// 会員なら10%割引 '// 関数の引数として直接渡せる MsgBox IIf(count > 0, "データがあります", "データがありません") |
3. クエリやSQL文での活用
Access VBAなどでクエリを構築する際、IIf関数を使うことでSQL文を簡潔に記述できます。
1 |
sql = "SELECT 名前, IIf(点数>=60, '合格', '不合格') AS 結果 FROM 成績表" |
4. 単純な値の選択に適している
副作用のない定数や変数の選択であれば、IIf関数は安全かつ効率的に使用できます。
1 2 3 |
status = IIf(isActive, "有効", "無効") color = IIf(temperature > 30, vbRed, vbBlue) displayName = IIf(Len(nickname) > 0, nickname, fullName) |
推奨されるIIf関数の使い方
IIf関数を使用する場合は、以下の点に注意してください。
- 第二引数と第三引数には、副作用のない単純な値や式のみを使用することが推奨されます。
- 関数呼び出しやメソッド実行など、実行されること自体に意味がある処理は引数に含めないようにしましょう。
- 複雑な条件分岐や副作用を伴う処理には、通常のIf文を使用する方が安全で可読性も高くなります。
IIf関数は便利に見えますが、上記のような特性を理解した上で使用する必要があります。特にチーム開発では、IIf関数の挙動を知らないメンバーがコードを読む可能性もあるため、明確さと保守性の観点から、通常のIf文を使用することをお勧めします。
コードの簡潔さよりも、意図が明確で予測可能な動作をするコードを書くことを優先しましょう。