エクセルマクロ・VBA達人養成塾 小川です。
昨日のブログ
で、「フォーカス・リーディング」の寺田昌嗣さんから依頼されて作ったマクロを公開しました。
その中で、Iif関数の挙動について「?」と思ったことについて書きましたが。
超優秀な元受講生さんからの助言で解決(というか、バグではなかったことが分かった)したので今日はその話題を。
Iif関数は、以下の書式で書きます。
Iif(条件式, 条件式がTrueのときにやる処理, 条件式がFalseのときにやる処理)
関数ですから、Left関数、Mid関数等々と同じように
hensu = Left("なんとかかんとか", 3)
のように、
hensu = Iif(hoge > 3, 5, 7) '[a]
というように書きます。
上記の式であれば、変数hogeの値が3より大きければhensuには5という値が入ります。
上記の式であれば、変数hogeの値が3より小さければhensuには7という値が入ります。
つまり、上記の式であれば、結果として起こることは以下と同じ。
If hoge > 3 Then hensu = 5 '[1] Else hensu = 7 '[2] End If
ところが、Iif関数は、If文と異なり、条件式の値がTrue/Falseどちらに転ぶかにかかわらず、「条件式がTrueのときにやる処理」、「条件式がFalseのときにやる処理」の両方をとにかくやっちゃう、という性質があります。
If 文なら、 [1], [2] のどちらかしか実行されません。
でも、ざっくり言うと、 Iif関数では、[1], [2]の両方をやってしまうわけです。
そのことは、[a]のような式では問題になりませんが、
『「条件式がTrueのときにやる処理」と「条件式がFalseのときにやる処理」のそれぞれ、違うセルを結合する処理が入っている』となると、問題になります。
さて、ここで、変数hogeの値によって、「セルA1~A2」か、「セルA1~B1」かのどちらかだけを結合するマクロを書きたいとします。
そのためのサンプルとして、以下に、OK1, OK2, NG という3つのマクロを書いてみました。
そのうちの2つは、問題なく動きます。そして、1つは、おかしな挙動になります。
以下は問題ありません。このマクロは、変数hogeの値によって、セル範囲A1~A2か、A1~B1の、どちらかしか結合しません。
Sub OK1() Dim hoge As Long Dim hensu As Long hoge = 9 If hoge > 3 Then Range(Range("A1"), Range("A2")).Merge Else Range(Range("A1"), Range("B1")).Merge End If End Sub
以下も、問題ありません。このマクロも、変数hogeの値によって、セル範囲A1~A2か、A1~B1の、どちらかしか結合しません。
Sub OK2() Dim hoge As Long Dim hensu As Long hoge = 9 If hoge > 3 Then hensu = mg(Range("A1"), Range("A2")) Else hensu = mg(Range("A1"), Range("B1")) End If End Sub Function mg(r1 As Range, r2 As Range) As Integer Dim r As Range Set r = Range(r1, r2) Range(r1, r2).MergeCells = True mg = r.Count End Functio
ところがOK2をIifで表現しようとした以下は問題です。
以下の式は、 hoge の値の評価にかかわらず、 mg(Range(“A1”), Range(“A2”)) , mg(Range(“A1”), Range(“B1”)) の両方の処理を実行してしまいます。
Sub NG() Dim hoge As Long Dim hensu As Long hoge = 9 hensu = IIf(hoge > 3, mg(Range("A1"), Range("A2")), mg(Range("A1"), Range("B1"))) End Sub Function mg(r1 As Range, r2 As Range) As Integer Dim r As Range Set r = Range(r1, r2) Range(r1, r2).MergeCells = True mg = r.Count End Function
なぜかというと、前述したとおり、Iif関数は、If文と異なり、条件式の値がTrue/Falseどちらに転ぶかにかかわらず、「条件式がTrueのときにやる処理」、「条件式がFalseのときにやる処理」の両方をとにかくやっちゃう、という性質があるからです。
..と、そんな話の延長でした。
僕が当初書いたマクロでは、以下のようにさらに入れ子がいろいろ入っていました。
そのため、ステップイン実行していてもいまいち面倒くさくて、問題の真の理由はつきとめられないままでした(汗
Private Function Neco(r1 As Range, r2 As Range) As Range Set Neco = IIf(Rnd() > 0.5, r1, r2) End Function Private Function Mg(r1 As Range, r2 As Range) As Range Set Mg = Range(r1, r2) Range(r1, r2).MergeCells = True End Function Private Function IsBk(rT As Range) As Boolean IsBk = rT.Interior.Color = vbBlack End Function Sub Main() Set rRet = IIf( _ IsBk(rA(1)), _ Mg(rA(0), rA(1)), _ Mg(rA(0), rA(2)) _ ) End Sub
ということで、Iif関数は仕様どおりの挙動でした。
僕のほうが仕様を正確に理解していなかった、ということでした。