はじめに
プロシージャは「手続き」という意味があります。
VBAでは一連の動作をするプログラムの塊を指し、「関数」と呼ばれることがあります。
プロシージャ(関数)は、上のようにインプットに相当する「引数」(ひきすう)と、アウトプットに相当する「返り値」があります。
また、「引数」や「返り値」は必ずなければいけないわけではありません。
プロシージャの書式
プロシージャは以下のように書きます。
Sub プロシージャ名 ( 引数名1 As データ型 , 引数2 As データ型 )
内部処理
End Sub
Function プロシージャ名 ( 引数名1 As データ型 , 引数2 As データ型 ) As 返り値データ型
内部処理
プロシージャ名 = 値
End Function
返り値
Subプロシージャは返り値を持ちません。
Functionプロシージャは返り値を持つことが出来ます。(返り値はなくても構いません。)
Functionで値を返す時は、以下のように値を返します。
プロシージャ名 = 値
引数
Subプロシージャ、Functionプロシージャは共に引数(ひきすう)を複数持つ事が可能です。
引数を複数使う時は、カンマで区切ります。
引数は、無くでも構いませんが括弧は省略できません。
引数にはデータ型を指定します。変数の宣言と同じように省略するとバリアント型となります。
引数名 As データ型
プロシージャ名
プロシージャ名は、呼び出される時に使いますのでVBAで既に使われている用語や、既に使われているプロシージャ名は避けなければいけません。プロシージャ名は日本語が使用できます。
プロシージャの書き方
プロシージャの様々な書き方を実例で示します。
引数、返り値なしの場合
Sub Macro20()
MsgBox "Hello VBA!"
End Sub
Function Macro21()
MsgBox "Hello VBA!"
End Function
引数なしの場合は、括弧内は何も書きません。Functionも同じように書けますが、このような場合はSubで書く事が多いでしょう。
引数を指定する場合
引数を指定すると、単独では実行できなくなり、他のプロシージャから呼び出さなければなりません。プログラムを書いている時は、そのプロシージャがきちんと動作するかどうかテストするためにテストコードを書いて確かめます。
Sub Macro22(str As String)
MsgBox "Hello " & str
End Sub
'上のコードを実行するためのテストコード
Sub testCode22()
Macro22 "山田"
End Sub
Sub testCode22a()
Call Macro22("山田")
End Sub
プロシージャの呼び出し方は2通りあります。Call を使う方法と使わない方法です。
Call を使わない場合は、プロシージャ名 引数1,引数2 という書式で書きます。
Call を使う場合は、Call プロシージャ名( 引数1,引数2 ) という書式で書きます。
(返り値の無い Function も書式は同じです。)
テストコードを実行すると「Hello 山田」とメッセージボックスが表示されます。
返り値を設定する場合
Functionで返り値を返す書き方には、あるパターンを知っておくと便利です。
まず冒頭で、返り値と同じ型の変数を定義します。(1)
次に、その変数を初期化しますが、この時、何も起こらなかった時の値を入れておくと便利です。(2)
それ以降に、必要な処理を書いていき、必要に応じて変数を書き変えます。
最後に、返り値用の変数を出力するようにします。(3)
今回、Booleanという変数が出てきましたので解説しておきます。
ブール型(True か False を返す変数)
Booleanはブール型で、True(真) か False(偽) のどちらかの値しか取りません。
主にIf文などの条件式の結果として使われ、結果がTrueならば条件が通り、Falseならば条件が通らない事になります。宣言した時の初期値はFalseですが、きちんと初期化してから使うようにしましょう。
'0ならTrueを返す
Function IsZero(num As Long) As Boolean
Dim b As Boolean '(1)返り値と同じ型の変数を用意
b = False '(2)初期化しておく
If num = 0 Then
b = True
End If
IsZero = b '(3)最後に返り値用の変数で返す
End Function
Sub testCode26()
Dim n As Long
Dim i As Long
For i = 1 To 5
If IsZero(i - 3) Then
Debug.Print "計算不可"
Else
Debug.Print "10/" & (i - 3) & " = " & 10 / (i - 3)
End If
Next i
End Sub
IsZero関数は、引数が0の時にTrueを返す単純な関数です。
テストコード(testCode26) では、If 文の条件式として使われています。
For文で i が 1,2,3,4,5 と値が変化しますが、i – 3 と渡されるので、
-2, -1, 0, 1, 2 となり3番目でTrueが返ります。
分母が0となる割り算はエラーとなりますので、これを防いでいるプログラムという事になります。
今回のプロシージャの呼び出し方は、前の2種類とは違う書式です。
If IsZero(i – 3) Then
Call の付いた書き方と同じで括弧付きの書き方ですが、Call を書きません。
値を代入するような場合でもこのような書き方になります。
例: num = Macro(100)
実行結果は以下のようになります。
10/-2 = -5
10/-1 = -10
計算不可
10/1 = 10
10/2 = 5
引数の扱いに注意
引数を渡す場合に、渡した先のプロシージャで値が書き換えられてしまうケースがありますので、注意が必要です。
以下のプログラム(testCode27)では、num は 1 として動作して欲しいのですが、11 となっています。
Function macro27(n As Long) As Long
n = n + 10
macro27 = n
End Function
Sub testCode27()
Dim num As Long
Dim ans As Long
num = 1
ans = macro27(num)
Debug.Print "ans = " & ans 'ans = 11
Debug.Print "num = " & num 'num = 11 ???
End Sub
この現象は、macro27 に引数を呼び出した先で、値が加工されてしまっている事が原因です。
n = n + 10
の部分で、引数に渡した num の値が書き換えられて、testCode27 の方でも変更が生きているためです。引数の渡し方には、「参照渡し」と「値渡し」の2種類があります。VBAでは、何も設定しない場合、参照渡しとなります。
このトピックは初心者には難しいのでこれを回避する方法を解説します。
(気になる方はこちら「引数の値渡しと参照渡し」を参照してください。)
参照渡しの回避方法は1つのルールを守ればOKです。
以下のプログラムの問題点は、左辺に引数の変数が来ているために値が変更されてしまっている所です。
Function macro27(n As Long) As Long
n = n + 10 '左辺に引数の変数が来て代入が起こってしまうのが問題
macro27 = n
End Function
これを回避するためには、左辺に引数の変数が来ないように書けば良いのです。
Function macro27(n As Long) As Long
macro27 = n + 10
End Function
上のように返り値を返す部分に直接計算式を充てるか、
前にやったFunctionのパターンに則った方法で書けば問題ありません。
Function macro27(n As Long) As Long
Dim d As Long
d = n + 10
macro27 = d
End Function
改めて実行してみると、「num = 1」 と思った通りの結果が得られます。
Sub testCode27()
Dim num As Long
Dim ans As Long
num = 1
ans = macro27(num)
Debug.Print "ans = " & ans 'ans = 11
Debug.Print "num = " & num 'num = 1
End Sub
まとめ
プロシージャの使い方に関しては、
Subは返り値を持たない、Functionは返り値を返す。
と覚えておけば良いでしょう。
引数に関しては、きちんと変数型を書くように心がけましょう。
プロシージャを呼び出す際の書き方に付いては何種類かありました。
値を返さない場合
Macro22 “山田”
Call Macro22(“山田”)
値を返す場合
If IsZero(i – 3) Then
num = Macro(100)
また、引数は参照渡しになるというも注意点です。防止する方法としては、左辺に引数の変数を置かないというルールを守りましょう。
今回出てきた変数のブール型も、良く出てくる変数型なので使い方を覚えて置きましょう。True と False だけの型なので分かり易いと思います。
プログラムに慣れてくると、Subの引数で参照渡しを使って引数の値を変更させて返り値のような使い方をするテクニックを使ったりします。
ただ、初心者のうちは分かり易いコードを書く事を心がけるようにしましょう。
入門講座 目次
・開発環境を整える
・VBAプログラムの基礎
・VBAプログラムの基礎2
・セルの使い方
・ブックやシートの参照
・プログラムでの日付の扱い方
・プロシーシャの使い方
・「マクロの記録」を利用する
・デバッグのやり方
・やりたい事の調べ方と解決方法
・自力でプログラムを書いてみる
・別ブックのデータを集計
・別ブックのデータを集計 2
コメント