【VBA】GoTo文は可読性を下げるのか?

プログラミング業界でよく言われていることの一つに「goto文は可読性が悪くなるので使ってはいけない」ということがあります。

私も新卒の頃にその鉄則を先輩から叩き込まれました。そのため、VBAでもgoto文は極力使わないようにコーディングをしてきました。

それは概ね正解だと思いますが、goto文を使用したほうがわかりやすくなるというケースも有り、現在では「絶対に使用しない」という信念は持っておりません。

わかりやすくなると思うケースについて記載をしてみたいと思います。

on error gotoは積極的に使うべき

はじめに、on error gotoはtry catch文の代わりとなるものなので、この記事では言うgoto文には含めないこととします。

on error gotoを使用しないと、想定外のエラーが発生した時に、VBAのプロジェクトが開いてエラーが表示されてしまうため非常に格好悪いです。

必ず、on error gotoは使用して専用のエラーメッセージをハンドリングするようにしましょう。

この記事で扱うgoto文は、エラーが発生していない状況で別のステップに処理を移す目的で使用するgoto文になります。

ループの中でスキップ目的で使うGoTo文

他の言語には、for文のループなどを強制的に抜け出すbreak文や、スキップするcontiune文が用意されています。

しかし、VBAの場合にはExit Forというbreak文の代わりがありますが、continueの代わりはありません。

そんな時に、goto文を使用してfor文をスキップさせるのは非常にわかりやすいです。

例えば「i = 3のときは処理を実行しない」という内容を書く時

Sub test()

    For i = 0 To 10
        If i <> 3 Then
            '何らかの処理
            
        End If
    Next i
End Sub
Sub test()

    For i = 0 To 10
        If i = 3 Then GoTo continue
        '何らかの処理
continue:
    Next i
End Sub

上がGoTo文を使わずにIf文でスキップする例、下がGoTo文でスキップをする例になります。

どちらのほうがわかりやすいと思いますか?

上記は簡単な例なので「どちらでも変わらない。むしろIf文のほうが良い」と思われるかもしれません。

しかし、「何らかの処理」と書いてある部分に100ステップ以上のコードがあったらどうなるでしょうか。

If文のネストが非常に深くなってしまい、「i <> 3」という条件がどのコードまでに適用されるのか探さなくてはいけません。

一方でGoTo文を使用する例だと、間のコードがどれだけ長くなったとしても、3の場合はスキップするというのがすぐに読み取れます。


後処理に飛ばすためのGoTo文

もう一つよく使うのは「Exit Sub」をしたいのだけど、後処理もしっかりしておきたいというケースです。

具体的にソースで説明してみたいと思います。

Sub test()
    Dim d As String
    d = Dir("C:\*.txt")

    If d = "" Then
        Exit Sub
    End If
    
    '何らかの処理
    
    '後処理
    Dir (vbNullString)
    
End Sub

上記はCドライブ直下にあるテキストファイルのパスを取得し、何らかの処理を行うコードです。

ただ取得できなかった場合はExitSubで終了します。

そのまま終了してしまうと、Dirで実施したい後処理の「Dir (vbNullString)」が実行されないという問題があります。そこで

Sub test()
    Dim d As String
    d = Dir("C:\test\*.text")

    If d = "" Then
        GoTo PostProcess
    End If
    
    '何らかの処理
    
PostProcess:
    '後処理
    Dir (vbNullString)

End Sub

Exitするのではなく、後処理がある場所にGoto文で飛ばしてあげることで後処理を実行するようにします。

「Exit Subする前にDir (vbNullString)すればGoto文不要だろ。」と思われるかもしれませんが、仮に後処理が複数になるとソースの重複が多くなります。

Sub test()
    Dim d As String
    Dim fso As New FileSystemObject
    d = Dir("C:\test\*.text")

    If d = "" Then
        Set fso = Nothing
        Dir (vbNullString)
        Exit Sub
    End If
    
    '何らかの処理
    
    '後処理
    Set fso = Nothing
    Dir (vbNullString)

End Sub

↑後処理が増えるほど、同じソースを書かなければいけなくなっていく

また、Exitする条件が増えた時に同じソースを書いていく場所も増えてしまうというデメリットもあります。

そのため、後処理の場所にGoTo文で飛ばしてあげるのがベストだと思います。

上に戻るGoTo文はあまり使わない

逆にあまり使わないケースとしては、呼び元のステップより上に戻るGoTo文ですね。

例えばですが、

Sub test(i As Integer)

Start:
    i = i + 1

    If i = 3 Then GoTo Start

    MsgBox i
End Sub

引数で与えられた数を+1する。ただし結果が3になる場合は、更に+1する。

という要件で作ったコードです。結果が3の場合は、最初に戻って更に+1しています。

これはソースの記載量は少ないのですが、可読性は低いです。iの値がどのように変化していくのかを読み解くために、どのように処理が遷移するのか考えなければいけなくなるためです。

前述したGoTo文を使うべきとしたコードでは、自ステップの下にGoToしているので、このような問題は発生しませんでした。

上に戻るような使い方をすると途端にわかりにくくなってしまいます。


コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)