和風スパゲティのレシピ

日本語でコーディングするExcelVBA

コロン:を使って複数行のコードを1行に書く

読みやすいコードの書き方に関する小ネタです。

ズバリ

Dim i As Long: i = 1

これをやるのはアリなのか?という話です。


VBAでは、「:」を使うことで、複数行のコードを1行に書くことができます。
これをマルチステートメントと呼びます。

これを使うべきか、使わないべきか。


結論から言うと

  • 使った行は読みづらくなる。
  • 代わり全体の流れが読みやすくなるなら使ってOK

と思っています。

ずらずら理由を書いていきますね。

マルチステートメントを使った行は見にくくなる

極端な例から行きます。

Dim i As Long: For i = 1 To .Count: Cells(i, 1) = i: Next

↑はA列に連番を入力しています。

イラっと来るレベルで見づらいですね(笑)


分解するとこれ↓

Dim i As Long
For i = 1 To .Count
    Cells(i, 1) = i
Next

こんなわかりやすい処理すら難読化するので、
これだけ見ると、あまり使ってはいけない気がします。

マルチステートメントは、使った行を読みにくくする

ことは、基本として認識しておきましょう。

処理1つの読みやすさ < 全体の流れの読みやすさ

マルチステートメントは、使った行を読みにくくします。
その前提でこのコードを見てください。

' オートフィルターのデータエリアをすべて処理
Dim R As Long
Dim R1st As Long: R1st = ws処理シート.AutoFilter.Range.Row + 1
Dim RLast As Long: RLast = ws処理シート.AutoFilter.Range.Row + ws処理シート.AutoFilter.Range.Rows.Count - 1
For R = R1st To RLast

    ~データ1行ごとの処理(Cells(R, ○○), ・・・)Next

どうでしょう?
変数3つの関係と使い道が、わかりやすい気がしませんか?

確かに1行1行の処理(オートフィルターの位置を取得している)は読みづらくなってしまっていますが、「オートフィルターのデータエリアをすべて処理」というコメントがあれば、別に読み飛ばしていい部分です。


プログラムは「その行で何をしているか」よりも、「全体を通してどんな流れの処理をしているか」の方が重要で、そして読み解くのが難しい部分でもあります。

処理の中身が読みづらくなる代わりに、全体の流れがつかみやすくなる
ような書き方ができそうだと思えば(+その処理の中身がさして重要でなければ)
マルチステートメントは使ってOKだと思います。


例えば、あのイラっと来る例に挙げた「連番をつける処理」も、

処理A(20行くらい) : データをランキングするための細かい計算と並び替え

Dim i As Long: For i = 1 To .Count: Cells(i, 1) = i: Next ' データに連番を付与

処理B(20行くらい):つけたランキングと密接にかかわるデータの加工

これだったら、AとBが近いほど読みやすいかもしれないので、
まあ許せなくもないです。(さすがにやらない方がいいとは思いますけどね)

関数にするのがベスト

ここまではマルチステートメントいいねって書いてきました。

しかし、この「処理を見にくくする代わりに全体を読みやすく」という役割において、
マルチステートメントをはるかに超える力を持ったライバルがいます。

ズバリ「関数=プロシージャ」です。

百聞は一見に如かず。

' オートフィルターのデータエリアをすべて処理
Dim R As Long
For R = GetR1stオートフィルター(ws処理シート) To GetRLastオートフィルター(ws処理シート)

    ~データ1行ごとの処理(Cells(R, ○○), ・・・)Next

' オートフィルターの位置取得関数(汎用関数のモジュールにでも書いておく)
Function GetR1stオートフィルター(ws対象シート As Worksheet) As Long
    GetR1stオートフィルター = ws対象シート.AutoFilter.Range.Row + 1
End Function
Function GetRLastオートフィルター(ws対象シート As Worksheet) As Long
    GetRLastオートフィルター = ws対象シート.AutoFilter.Range.Row + ws対象シート.AutoFilter.Range.Rows.Count - 1
End Function

これはもう関数の圧勝ですね。

関数は、処理を見にくくするどころか、処理が見えなくなります。
その代わりにその部分に名前を使られるので、ものすごく処理の流れが見やすくなります。

しかも、別の場所に使いまわしが効くというおまけつき。

  • 意味さえ分かれば、中の処理は重要でない
  • なるべくその部分を1行で済ませたい
  • 全体の流れに邪魔なくらい何回も出てくる

を解決するのは、まさに関数の真骨頂です。
そこは忘れないようにしておきましょう。

あくまでマルチステートメントは補助的な使い方で。

おまけ:If文はマルチステートメントにできない

実は「If」には:が使えません。

より正確には、:の後に「End If」を書くとエラーになります。

もし使えたとしても「分岐を1行で表現しよう」なんて暴挙には出ないと思うので、
この仕様を知っている意味はないと思いますが。


ちなみにIf文は、Elseなし単行の場合は、「:」がなくても1行で書けます。

If isデータの入力不備がある Then Exit Sub

こちらは便利なので覚えておきましょう。

おまけ:マルチステートメントはエラーで再開できない

マルチステートメントでエラーが発生した場合、
その部分を書き換えようとすると、

このアクションを実行するとプロジェクトがリセットされます。実行しますか?

になってしまうので、「エラーを直してその場所から再開する」ことができません。

例えば

Dim i As Long: i = "あ"

↑この行で止まったとき、あを1にして、再開することはできません。

その場でトライ&エラーを繰り返して直したくなるような複雑な処理は、
マルチステートメントになんかしないので、こちらも割とどうでもいい知識です。

ちょっとイラっと来たことはありますが、この仕様で困ったことはありません。