擬似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