Excel VBAのプロシージャ(関数)について

ExcelVBA

プロシージャの種類

VBAには、サブプロシージャ(Sub)とファンクションプロシージャ(Function)の2つの主要なプロシージャの種類があります。サブプロシージャは通常、引数が設定可能で特定のタスクを実行するために使用されます。Excelではマクロとして認識されますが、値を返すことはできません。

一方、ファンクションプロシージャは引数を設定して値を返すことができるため、計算を渡したり値の取得などの用途に適しています。また、マクロとしては認識されないためサブプロシージャから呼び出しを行わなくては利用できません。

プロシージャの種類値を返すかマクロとして識別されるか引数は設定できるか
サブプロシージャ返さないされるできる
ファンクションプロシージャ返すされないできる
プロシージャの特徴

今回は、それぞれのプロシージャの機能と実装方法について説明します。

引数の渡し方(値渡しと参照渡し)

プロシージャには引数を渡すことができます。
渡した引数を利用して、計算・変数の反映・値を返すなどの処理を行うことができます。

値渡し(byVal)

値渡し(ByVal)は、引数の値をコピーして渡す方法です。値渡しでは、呼び出し元の変数の値が変更されても、元の変数には影響を与えません。渡された引数は、新たな変数として扱われます。これは、関数の引数を値渡しで受け取る場合や、サブプロシージャで引数を変更したくない場合に適しています。

以下は値渡しの例です。

Sub ValuePassingExample()
    Dim x As Integer
    x = 10
    
    ' サブプロシージャに値渡しによって変数を渡す
    Call ModifyValue(x)
    
    ' xの値は変更されない
    MsgBox "値渡しの結果:" & x
End Sub

Sub ModifyValue(ByVal num As Integer)
    num = num + 5
End Sub

この例では、ModifyValueサブプロシージャに変数xを値渡しで渡しています。ModifyValue内で引数numを変更しても、元の変数xには影響を与えません。そのため、メッセージボックスに表示されるxの値は変更されずに10のままです。

参照渡し(byRef)

参照渡し(ByRef)は、引数のアドレス(参照)を渡す方法です。参照渡しでは、呼び出し元の変数のアドレスが渡されるため、呼び出されたプロシージャ内で引数を変更すると、元の変数にも変更が反映されます。これは、関数の引数を変更し、その変更を呼び出し元で反映させたい場合や、大きなデータ構造を効率的に処理する場合に適しています。

以下は参照渡しの例です。

Sub ReferencePassingExample()
    Dim y As Integer
    y = 10
    
    ' サブプロシージャに参照渡しによって変数を渡す
    Call ModifyReference(y)
    
    ' yの値が変更される
    MsgBox "参照渡しの結果:" & y
End Sub

Sub ModifyReference(ByRef num As Integer)
    num = num + 5
End Sub

この例では、ModifyReferenceサブプロシージャに変数yを参照渡しで渡しています。ModifyReference内で引数numを変更すると、元の変数yの値も変更されます。そのため、メッセージボックスに表示されるyの値は変更後の15となります。

引数にオプションを記載しない場合

引数にオプションを指定しない場合、デフォルトでは参照渡しとなります。つまり、引数に指定された変数はそのままの形でプロシージャ内で使用され、値のコピーではなく元の変数への参照が渡されます。参照渡しの利点は、プロシージャ内で引数の値を変更すると、元の変数の値も変更されることです。しかし、注意が必要であり、引数にオプションを指定することで値渡しに切り替えることも可能です。

Sub DefaultArgumentExample()
    Dim x As Integer
    x = 10
    
    ' サブプロシージャに引数を渡す(オプションを指定しない)
    Call ModifyDefaultArgument(x)
    
    ' xの値が変更される
    MsgBox "参照渡し(デフォルト)の結果:" & x
End Sub

Sub ModifyDefaultArgument(num As Integer)
    num = num + 5
End Sub

この例では、ModifyDefaultArgumentサブプロシージャに変数xを引数として渡していますが、オプションを指定せずに引数を定義しています。この場合、デフォルトでは参照渡しが適用されます。

ModifyDefaultArgument内で引数numを変更すると、元の変数xの値も変更されます。そのため、メッセージボックスに表示されるxの値は変更後の15となります。

引数を使わないで値を共有する方法

引数を利用しない方法としては、モジュールレベルの変数を使う方法があります。

モジュールレベル変数は、VBAモジュール内で宣言され、そのモジュール内の複数のプロシージャで使用される変数です。モジュールレベル変数はグローバルスコープを持ち、モジュール内のどのプロシージャからでもアクセスできます。以下は、モジュールレベル変数を利用する例です。

Option Explicit

Dim counter As Integer ' モジュールレベル変数

Sub ModuleLevelVariableExample()
    counter = 0 ' モジュールレベル変数に初期値を設定
    
    ' サブプロシージャを3回呼び出してモジュールレベル変数を増やす
    IncrementCounter
    IncrementCounter
    IncrementCounter
    
    ' 結果を表示
    MsgBox "カウンタの値:" & counter
End Sub

Sub IncrementCounter()
    counter = counter + 1 ' モジュールレベル変数を増やす
End Sub

この例では、ModuleLevelVariableExampleサブプロシージャでモジュールレベル変数counterを初期化し、IncrementCounterサブプロシージャを3回呼び出してcounterを増やしています。

IncrementCounter内でモジュールレベル変数counterを操作しているため、複数の呼び出しで値が累積されます。最終的にModuleLevelVariableExampleでメッセージボックスに表示される値は3となります。

モジュールレベル変数はモジュール内でのみ有効であり、他のモジュールやワークブック内の他のモジュールからはアクセスできません。ただし、グローバルモジュール(「ThisWorkbook」モジュールや「Sheet」オブジェクトのモジュールなど)に宣言されたモジュールレベル変数は、プロジェクト内の他のモジュールからもアクセスできます。