擬似continue
「VBAのイマイチなところ選手権」でもやったら、かなり上位に食い込むだろうと思うのが、
Forループでcontinueが使えない
ことだと思う。
breakに相当する命令があるだけに、なおのこと歯痒いことだろう。
テスト用コード
リスト1 標準モジュール
Public Sub testContinue() Dim ar As Variant ar = Array("アホ", "バカ", "クズ", _ "カス", "デコスケ", "ロクデナシ", _ "ウジムシ", "ボケ", "スットコドッコイ", _ "ち~んw") Dim i As Long For i = 0 To 9 Debug.Print ar(i) Next End Sub
要素数10の配列を準備して、各要素をDebyg.Printでイミディエイトに書き出すだけのコード。
たとえば、こいつを「3の倍数個目は出力しない」みたいな条件で作動させることを考える。
Forブロック内部をIfブロックにおさめる
continueしたい条件のときは何もしない、ということを、If文で実現する考え方。
リスト2-1 標準モジュール
Public Sub testContinue() Dim ar As Variant ar = Array("アホ", "バカ", "クズ", _ "カス", "デコスケ", "ロクデナシ", _ "ウジムシ", "ボケ", "スットコドッコイ", _ "ち~んw") Dim i As Long For i = 0 To 9 If ((i + 1) Mod 3) = 0 Then Else Debug.Print ar(i) End If Next End Sub
もちろん、これで意図した通りの出力は得られるが、処理の本体がそこそこのサイズの場合、全体をIfブロックの中身にする、というのはあまりにブサイク。
Nextの手前にラベルを置いてGoToでジャンプする
題名の通り。Nextの直前にラベルを置いておいて、continueする代わりにGoToでジャンプするやり方。
リスト2-2 標準モジュール
Public Sub testContinue() Dim ar As Variant ar = Array("アホ", "バカ", "クズ", _ "カス", "デコスケ", "ロクデナシ", _ "ウジムシ", "ボケ", "スットコドッコイ", _ "ち~んw") Dim i As Long For i = 0 To 9 If ((i + 1) Mod 3) = 0 Then GoTo JumpTo Debug.Print ar(i) JumpTo: Next End Sub
For文の入り口で条件を確認して、条件に当てはまっていたらNextの手前まで飛ぶので、これでもまあ、意図通りの出力が得られるだろう。
ただ、ラベルは必ず左端に配置されてしまうので、インデントが狂ってしまう。これまたブサイク。
プロシージャを呼び出してループカウンタをインクリメントする
ちょっとこういうおバカなやり方を実験してみた。continueする条件に当てはまっていたら、ループカウンタをその場でインクリメントしてみるw
リスト2-3 標準モジュール
Public Sub testContinue() Dim ar As Variant ar = Array("アホ", "バカ", "クズ", _ "カス", "デコスケ", "ロクデナシ", _ "ウジムシ", "ボケ", "スットコドッコイ", _ "ち~んw") Dim i As Long For i = 0 To 9 If ((i + 1) Mod 3) = 0 Then continue i Debug.Print ar(i) Next End Sub Public Sub continue(ByRef i As Long, _ Optional ByVal step_ As Integer = 1) i = i + step_ End Sub
ループカウンタを参照渡しでcontinueプロシージャに渡す。受け取ったcontinueプロシージャ側では、ループカウンタをインクリメントするだけ。値渡しだと、「i」は呼び出し側と呼び出され側で別物扱いになるので、珍しく参照渡し。これだとcontinueプロシージャ側での計算結果が呼び出し元の「i」にも反映される。
実行結果
いちおう、意図通りの出力が得られた。
おわりに
もちろん、3つ目のやり方が重大な問題(笑)をはらんでいる(したがって使いものにならない)ことは重々承知の上ですw