【VBA入門】教科書通りじゃなくていい!初心者が無視してもよいVBAのセオリーや構文

VBA
スポンサーリンク
最近VBAを勉強してるんですが、覚えることが多すぎて苦労しています・・・
中の人
中の人

プログラミングで初心者が覚えるべきなのは「何を覚えないといけないか」ではなく「何を覚えなくてよいか」だと思います。

そこを今回の記事では紹介していくね!

今回の記事では、プログラミング未経験者がVBAを覚えようとする場合に、始めは無理に覚えなくても良いVBAのセオリーや構文を紹介していきます。
 
 

初心者が最初から使えなくてもよいVBAのセオリーや構文とは

プログラミングの教科書を読むと、言語固有の様々な構文やセオリーなどがまとめられており、それらを最初からすべて理解するのは大変です。

VBAにおいても、プログラムを安全に動かすための書き方のルールや、少ないコード量で効率よく処理を実装するセオリーなどもありますが、最初はそこまで気にする必要はなく、プログラミングやVBAに慣れてから徐々に意識していけばよいものも多くあります。

子供が言葉を覚えていく過程でも、最初は片言ですし、意思を伝えることが優先ですし、文法なんて気にしません。
それでも片言のコミュニケーションを何度も繰り返していくことで、次第に文法も身に付けていきます。

プログラミングの世界でも同じであり、プログラミングの上達は、まずは不格好でも動くものをどんどん作っていくことが大事です。
 
 

無理に使わなくてもよいセオリーや構文の紹介とその理由

当項では、VBAにおける無理に使わなくてもよいセオリーや構文などを理由も交えて紹介していきます。
これらの項目は、一般的なVBAの教科書では当たり前のように使うものとして書かれていますが、実際には最初は無視してもらってよいものです。
 

Withステートメントは可読性が下がるので使わない

Withステートメント」は、オブジェクト単体や修飾したオブジェクトを冒頭で定義することで、オブジェクトの完全修飾を省略することができる記述方法です。
構文としては、最初に

With オブジェクト
と定義して、最後に
End With

を指定することで、WithからEnd Withで囲まれた範囲の行では、オブジェクトの修飾を省略できます。

参考までに、MicrosoftのVBA公式リファレンスにある「With ステートメント」の解説リンクも貼っておきます。

Withステートメントを使ったサンプルコード

Option Explicit

Sub test()

    'With有りサンプル
    With Sheets("Sheet1")
        .Range("A1").Value = "テストA1"
        .Range("A2").Value = "テストA2"
        .Range("A3").Value = "テストA3"
    End With

    'With無しサンプル
    Sheets("Sheet1").Range("B1").Value = "テストB1"
    Sheets("Sheet1").Range("B2").Value = "テストB2"
    Sheets("Sheet1").Range("B3").Value = "テストB3"

End Sub
サンプルコードの解説

このコードは、Excel VBAのサンプルです。

With有りサンプルとWith無しサンプルでは、Sheet1の列Aと列Bのセルに値を書き込んでおり、処理内容は同じです。

With無しサンプルのコードは同じ記述が並んでおり無駄が多く、With有りサンプルのコードの方が洗練された印象です。

VBAに慣れた人であれば、コードの記述が省略できることで効率的にコードを記述できますし、書かれたコードの文字数も減り、見た目もきれいになります。

VBAの教本などでもWithが理解できていることを前提として説明されている場合も多いのですが、初心者の場合は無理に使わなくてもよい構文です。
 

Withステートメントを使わなくてもよい理由

VBA経験者であれば便利な構文ですが、初心者の場合はWithでオブジェクトの指定を省略してしまうことで、修飾されたオブジェクトの元のオブジェクトが同じ行内に並ばなくなり、コードの可読性が下がります。

要するに、コードをぱっと見て処理を解析する場合の手間が増えることになります。

また、初心者にとってコードを何度も書くことは、プログラミングを習得する場合に、非常に重要な要素になります。
何度も同じコードを書くことで、その構文が記憶と体に定着します。

よって、初心者の場合はWithで記述を省略するのではなく、コードが冗長になろうが一行一行書いていくほうが上達に繋がります。
 

引数の参照渡しと値渡しを無理に使い分けなくてよい

VBAの場合は、SubプロシージャやFunctionプロシージャなどを作成した際に、その処理のパラメーターを引数として渡します。

この引数では、二種類の渡し方があり、その種類によって引数の挙動が異なります。

引数の参照渡しと値渡しの違い
種類 修飾子 説明
参照渡し ByRef 渡された引数の値を書き変えると、引数の元となる変数の値も書き変わる。
値渡し ByVal 渡された引数の値を書き変えても、引数の元となる変数の値は変わらない。

最初はどっちが参照渡しでどっちが値渡しかが覚えづらいと思いますが、Byが「~からの」とか「~によって」の意味合いであり、ByRefはReference(参照)、ByValはValue(値)をそれぞれ略していると覚えてもらえれば覚えやすいと思います。

また、SubプロシージャやFunctionプロシージャの引数にByRefやByValを明示的に指定しない場合、VBAでは既定でByRef(参照渡し)が使われます。

この参照渡しと値渡しは、安全なプログラムを実装したり効率良く処理を作成するにあたって、とても重要な言語仕様です。
 

参照渡しと値渡しを使ったサンプルコード

Option Explicit

Sub Main()

    Dim test As String
    
        '① 変数に初期値を代入します。
        test = "Hi!"
        MsgBox test
        
        '② 変数を値渡し引数のSubプロシージャに渡します。
        Call Sample_ByVal(test)
        MsgBox test
        
        '③ 変数を参照渡し引数のSubプロシージャに渡します。
        Call Sample_ByRef(test)
        MsgBox test

End Sub


'値渡し引数サンプルコード
Sub Sample_ByVal(ByVal a As String)

    a = "Changed!"

End Sub

'参照渡し引数サンプルコード
Sub Sample_ByRef(ByRef a As String)

    a = "Changed!"
    
End Sub
サンプルコードの解説

①では変数に値を代入してMsgboxでその変数の値を表示しています。

②では、渡された変数「test」をSubプロシージャ「Sample_ByVal」のなかで書き換えますが、値渡しなのでMsgboxで表示される文字列は Hi! のままです。

③では、渡された変数「test」をSubプロシージャ「Sample_ByRef」のなかで書き換えたことで、元の変数「test」も Changed! に書き変わります。

直観的には、引数で渡されてきたSubプロシージャやFunctionプロシージャ内で引数の値を書き換えた場合に、そのSubプロシージャやFunctionプロシージャの呼び出し元の処理で使用している変数の値まで書き変わることはイメージし辛いのではないかと思います。

値渡しでは文字通り「引数」として「値」を渡し、参照渡しではその変数の「メモリー位置」を渡します。
例えば、値渡しでは、変数の箱から値のみを取り出して引数として使用し、参照渡しでは、変数の箱ごと引数として使用するイメージです。
 

参照渡しと値渡しを無理に使い分けなくてもよい理由

前述したとおり、参照渡しと値渡しは呼び出し元の処理に影響を与える場合があり、できれば適切に使い分けるのが望ましいのですが、最初は特に意識しなくてもよいです。

VBAの場合、SubプロシージャやFunctionプロシージャで明示的に引数の種類を指定しない限り、既定値は参照渡しになりますが、常に引数の種類を指定せず、参照渡しだけしていても問題ないかと思います。

VBAの場合、大勢で一つのプログラムを作ることはなく、たいていは一人で作ります。
また、プログラミングを習得し出した最初からSubプロシージャやFunctionプロシージャが入り組んだ複雑なコードを書くことも無いかと思います。

他言語のように、複数人がチームとなって一つのプログラムを作る場合は、自身が作ったサブルーチンや関数を別の人が誤った使い方をして不具合を誘発することを防ぐためにも、参照渡しと値渡しは明示的に使い分けるべきですが、一人でプログラム全体を作り上げるなら、そこまで気をつかう必要はありませんし、参照渡しで渡されたきた変数に対して値を代入しないようなコードを書いていれば、既定値の参照渡しだけを引数として使用していても、特に問題は起こりません。

よって、最初はSubプロシージャやFunctionプロシージャの引数にはByRefやByValを付けずに、引数名と型だけ指定しておけば十分です。
 

プロシージャのスコープは指定しなくてよい

VBAに限らず、一般的なプログラミング言語では、「スコープ」という仕組みがあり、対象のプログラムや変数などが、そのプログラム全体のどの範囲まで使用できるのかを定義できます。

例えば、VBAのSubプロシージャやFunctionプロシージャであれば「Private」と「Public」の二種類のスコープがあります。

標準モジュール内に作ったプロシージャの場合、プロシージャ名の宣言時の先頭で Private と書き出すことで、そのプロシージャは同じモジュール内のプログラムからしか呼び出しできなくなります。
逆に、Public と指定することで、自身の所属するモジュール以外からも自身のプロシージャを呼び出せるようになります。

このスコープを適切に設定することで、プロシージャの呼び出し可能モジュールを制限し、誤って関係のないプロシージャが呼び出されてしまうことを防いだり、機能や用途ごとにモジュールを分割して、整理されたモジュールやプロシージャ構成を構築することができます。

大量にプロシージャを作成してアプリケーションを実装する場合には、このスコープを適切に使い分けることが重要です。
 

スコープを指定したサンプルコード

Option Explicit

'同一モジュール内からしか実行できないSubプロシージャ
Private Sub PrivateSubSample()

    '同一モジュールからの呼び出しだけを想定した処理。

End Sub

'同一モジュール内からしか実行できないFunctionプロシージャ
Private Fcuntion PrivateFuncSample() As Boolean

    '同一モジュールからの呼び出しだけを想定した処理。

End Function

'異なるモジュールからも実行できるSubプロシージャ
Public Sub PublicSubSample()

    '全てのモジュールからの呼び出されることを想定した汎用的な処理。

End Sub

'異なるモジュールからも実行できるFunctionプロシージャ
Public Sub PublicFuncSample() As Boolean

    '全てのモジュールからの呼び出されることを想定した汎用的な処理。

End Function

 

プロシージャのスコープを指定しなくていい理由

スコープにPrivateを指定するということは、本来できることに対して明示的に制限を掛ける行為です。
プログラミングやVBAを覚えたての頃は、知識がなくて出来ないことがいっぱいあるなかで、出来る方法を試行錯誤しながら模索していきます。

そんななかで、本来はできるのに敢えてできなく制限を掛ける機能を覚える必要はありません。
VBAでは、プロシージャのスコープの指定を省略することができます。
尚、モジュールのなかに作成したプロシージャのスコープの既定値は Public です。

だったら、SubプロシージャやFunctionプロシージャを作成する際に、いちいちスコープを指定する必要はなく、いきなり Sub ~ とか、Function ~ のようにスコープの指定を入れずに書き出してしまった方が楽です。

VBAの教本や学習サイトでは、初心者向けのサンプルコードでもしっかりスコープの指定がされているコードを目にしますが、VBAやプログラミングを覚えたての段階でスコープで呼び出し元や参照元のモジュールに制限を掛ける必要がある状況になることはまず考えられないため、スコープの概念自体は知識として知っておくにしても、それをいちいち使用して指定することはしなくても結構です。
 

クラスモジュールは使わず標準モジュールだけ覚えればよい

VBAでは「クラス」が使えます。
VBEの画面で左側の項目を右クリックして「挿入」を選択すると表示される「クラスモジュール」からクラスを追加できます。

クラスは所謂「オブジェクト指向プログラミング」においては重要な仕組みです。

過去に当ブログでも、ADOを使用したデータベース操作用クラスのコードを紹介しています。

この記事でも紹介しているクラスを使用することで、ADOを使用したデータベースへの接続処理や、SQLを実行してSELECT結果をレコードセットに取得したり、UPDATE文やINSERT文を実行する際のトランザクション管理処理が共通化され、個々のSubプロシージャやFunctionプロシージャ内でデータベースへ接続したりデータベースを操作する実装が非常に楽になります。

クラスの特徴としては、プロパティとして値やオブジェクトを保持することができて、メソッドとして振舞いを実装できます。

SubプロシージャやFunctionプロシージャの場合は、一つのプログラムが一つの処理を実行するだけですが、クラスの場合は一つのクラスにメソッドとして複数の処理(「振舞い」と呼んだり「操作」と呼んだりします。)を実装させることができます。
また、作成したクラスを使用する場合は、内部の処理を意識しなくても済むようになっています。

プログラムを効率的に作成していく場合に、SubプロシージャやFunctionプロシージャを使って処理を分割して共通化していくことは大事ですが、その「処理の共通化」をより効率良く実装する仕組みであり、現代のプログラミング設計においてなくてはならない言語仕様です。

クラスの説明は簡単ではなく、当記事の趣旨から外れるため割愛させていただきますが、参考としてVBAでクラスを実装したサンプルコードも紹介しておきます。
 

クラスモジュール使ったサンプルコード

クラスモジュール側コード
Option Explicit

'メンバ変数
Private a As String
Private b As Object

'インスタンス生成時に自動的に呼ばれます。
Private Sub Class_Initialize()
    '通常は初期化処理などを以下に実装します。
    
    Debug.Print "initalized"
End Sub

'インスタンス破棄時に自動的に呼ばれます。
Private Sub Class_Terminate()
    '通常は各種の保持リソースを解放する処理などを以下に実装します。

    Debug.Print "terminated"
End Sub

Public Sub MethodSample1()

    MsgBox a & ":メソッド"

End Sub

'プロパティで通常の値を受け取るなら Let を使います。
Property Let LetSample(LetVal As String)

    a = LetVal
    
End Property

'プロパティの値を参照させるなら Get を使います。
Property Get GetSample() As String

    GetSample = a
    
End Property

'プロパティでオブジェクトを受け取るなら Set を使います。
Property Set SetSample(objSample As Object)

    Set b = objSample

End Property

Public Sub MethodSample2()

    b.Range("A1").Value = "クラスで書き込み"
    
End Sub
クラス呼び出し例の標準モジュール側コード
Option Explicit

Sub ClassSample()

    Dim objTest As VBAProject.TestClass
    Dim objSheet As Object
    
        '①インスタンスを生成します。
        Set objTest = New VBAProject.TestClass
        
        '②プロパティに値を格納します。
        objTest.LetSample = "Hello!"
        
        '③プロパティから値を取り出します。
        MsgBox objTest.GetSample
        
        '④メソッドを実行します。
        objTest.MethodSample1
        
        '⑤オブジェクト変数を作成します。
        Set objSheet = Sheets("Sheet1")
        
        '⑥オブジェクト変数をプロパティに格納します。
        Set objTest.SetSample = objSheet
        
        '⑦メソッドを実行します。
        objTest.MethodSample2

        '⑧インスタンスを解放します。
        Set objTest = Nothing

End Sub

上記のコードでは、クラスモジュール名を「TestClass」と命名しています。
VBEでは以下のような構成になっているイメージです。

クラスモジュールの作成サンプル画像

サンプルコードの解説

当サンプルコードでは、クラスのプロパティに値を Let や Set で入れる処理や Get で取り出す処理、メソッドとして処理を実行させています。

Subプロシージャ「ClassSample」内の①の処理ではクラスモジュールで作成したクラスのインスタンスを生成しています。

②の処理ではプロパティ「LetSample」に値を入れています。

③の処理では②でプロパティに入れた値を取り出してMsgboxで表示させています。

④の処理ではプロパティ「LetSample」の値を使ってメソッド「MethodSample1」を実行しています。

⑤の処理ではSheetsオブジェクトをオブジェクト変数「objSheet」に格納しています。

⑥の処理ではプロパティ「SetSample」にオブジェクト変数を入れています。

⑦の処理ではメソッド「MethodSample2」を実行しており、セルに値を書き込みます。

⑧の処理ではインスタンスを破棄しています。

 

クラスモジュールを使わずに標準モジュールだけ覚えれば良い理由

クラスは習得することで効率的な実装ができて、非常に便利な仕組みですが、少なくてもVBAに限って言えば、クラスモジュールじゃないと実装できない処理は無いです。
殆どの処理は、標準モジュール内でSubプロシージャとFunctionプロシージャを作れば事足ります。

VBAのキャリアが長いベテランでも、クラスを使ったことがない人も結構居たりします。
VBAの場合はクラスを作れても、言語仕様として継承ができなかったり、別のプログラミング言語であれば普通に備わっている機能が実装されていないことで若干不便です。

また、そもそもクラスの特徴であるカプセル化や内部処理の隠蔽といったものは、チームで分担しながら大規模なアプリケーションを開発する場合であれば必須だと思いますが、個人で開発する場合はクラスを使うメリットはだいぶ小さくなります。
もちろんクラスの仕組みを適切に理解して使う場合は個人開発であっても十分便利ですが、プログラミング初心者にとってクラスを理解することは、かなり高いハードルです。

よって、VBAにおいて大半の処理は標準モジュールのSubプロシージャやFunctionプロシージャが使えれば作れるため、無理にクラスモジュールを作って苦労しながら処理を実装するよりも、SubプロシージャやFunctionプロシージャを適切に理解して使い分けられるようにする方がはるかに大事です。

VBAの技術が備わってくれば、いつかはクラスも覚えるときがくるので、それまではクラスモジュールの存在は忘れてしまって大丈夫です。
 
 

最後に

今回の記事では、VBA初心者やプログラミング初心者向けに、VBAを習得するにあたって、最初は覚えなくてよい、気にしなくてよいと個人的に考えるVBAのセオリーや構文などを紹介しました。

記事のなかでも書きましたが、最初のうちは、コードが冗長でも構わないですし、効率が悪い処理でも問題はないと思います。
まずは、自分が作りたい処理や機能を自分の知っている知識のなかで実装できるようになることが大事であり、コードの見栄えや、安全性、拡張性などは無視してひたすらコードを書きましょう。

ひたすらコードを書くことで、何度も書いた構文は知識から技術になります。
何度も同じコードを書いていれば、そのうちコードの記述を少しでも省略したい、再利用したいと思うようになり、今回紹介した構文やセオリーを自然と学ぶようになっていきます。

技術は必要な状況にならないとなかなか覚えられないものです。

今回も読んでいただきましてありがとうございました。
それでは皆さまごきげんよう!

タイトルとURLをコピーしました