ExcelVBAの解説
VBAには、2種類のプロシージャがあります。SubプロシージャとFunctionプロシージャです。
Sub で始まるプロシージャを指します。いままで解説してきたプロシージャですね。例えば次のようなプロシージャです。
Sub ShowMyName() MsgBox "僕の名前はTatsudaiです" End Sub
Subプロシージャには、処理を記述します。あいまいな言い方ですね。でも、次に説明するFunctionプロシージャを理解すると、その意味が分かります。
このプロシージャは、Functionで始まります。例えば次のようなプロシージャです。
Function getTomorrow() As Date getTomorrow = Date + 1 End Function
Function で始まるので、最終行は End Function で終わります。
ここで一番大切なことを言います。Functionプロシージャは、戻り値を持ちます。戻り値とは、答えのことです。
つまり、Function とは関数のことなんです。(そのまんまです)
Functionプロシージャの構文は次の通りです。
Function 関数名() As データ型
関数名 = 戻り値
End Function
コードの中で必ず戻り値の設定をおこないます。上記のサンプルコードでは、getTomorrow = Date + 1 の部分です。
ちなみに、Date は、今日の日付を返す(答えとして出すことを「返す」といいます)VBA用の関数です。今日の日付に1を足すので、明日の日付になります。
そう、このFunction プロシージャ getTomorrow は、明日の日付を返す関数となります。
日付が戻り値なので、データ型はDate になります。新しいデータ型を覚えましたね。(これで、Integer , String , Date の3つを取り上げましたよ)
答えを出すのがFunctionプロシージャなので、Subプロシージャの中で使ってもらう必要があります。
Sub showTomorrow() Range("C2").Value = getTomorrow End Sub
セルC2に、Functionプロシージャ getTomorrow の戻り値を設定しています。このSubプロシージャを実行すると、次のようになります。
今日は2/24 なので明日は 2/25 になります。このプロシージャを実行する日によってもちろん明日は変わってきます。念のため。
Excelの関数を思い浮かべてください。例えば、合計を出すSum関数は、必ず引数(ひきすう)を指定します。指定しないと、いくら頭のいいExcelでも合計を出すことができないからです。だって、どの合計を出したらいいのか 分からないのですから、答えの出しようがありませんよね。
言い換えると、受け取った引数の値に応じて、柔軟に答えを出すことができるのです。これって便利なことですよね。
Functionプロシージャも、引数を持つことができます。そのプロシージャは、受け取った引数の値に応じて答えを出します。
そんなFunctionプロシージャを作ってみましょう。
Function getNextMonth(mydate As Date) As Integer Dim d As Date d = DateAdd("M", 1, mydate) getNextMonth = Month(d) End Function
このプロシージャは、Date型(日付型)の引数を受け取って、その引数の翌月の数字を返す関数です。なお、日付を返すわけではなく数字を返すので戻り値のデータ型は Integer です。
引数には、適当な名前を付けておくのがルールです。今回はmydate としました。引数名には、変数名の命名ルールが適用されます。
それでは、コードの説明をしておきましょう。
Date型の変数d を宣言して、d にDateAdd関数の答えを代入しています。
DateAdd関数は、VBAの関数で、基準日に日付を加算した日付を返します。最初の引数に単位(今回は月を示すM)、2番目の引数には加算する数(今回は1)、そして3番目の引数には基準となる日付を指定します。今回は、基準日に1ヵ月を加算した日を返します。
3番目の引数にはFunctionプロシージャの引数mydate を指定しているので、mydateの値によって答えが決まります。
そして、プロシージャの戻り値には、変数d の月を取り出して設定しています。Month関数は、VBAの関数ですが、Excelの関数と同じように使えます。
さて、それでは、問題です。以下のようなシートがあります。セルC4には記念日の日付が入力されています。ただし、ひとによってこの日付は変わってきます。とりあえず2017/3/19 が入力されているとして、セルC5に記念日の翌月の数字を表示したいとします。どのようなプロシージャを作ればいいでしょうか?
Functionプロシージャ getNextMonth の出番ですよ。正解例を紹介します。(正しく動作すれば正解なので、書き方はいくつもありますが)
Sub showNextMonth() Dim dt As Date dt = Range("C4").Value Range("C5").Value = getNextMonth(dt) End Sub
日付型の変数dt を宣言し、dt にセルC4の値を代入しています。そして、Functionプロシージャ getNextMonth の引数にdt を渡し、戻り値をセルC5に設定(表示)しています。
さて、FunctionプロシージャgetNextMonth の引数のことを仮引数(かりひきすう)といいます。mydate という名前を付けましたね。
Functionプロシージャを実際に使用するときに受け取る引数を実引数(じつひきすう)といいます。dt という名前の変数を引数に設定していますね。
このように、借り引数の名前と実引数の名前は別に一致しなくても構いません。重要なのは、引数のデータ型が一致しているかどうか、だけです。
実行結果は以下の通りです。なお、セルC4には、2017/3/19が入力されているものとします。
セルC5には、翌月の 4 が表示されていますね。セルC4の日付を自由に変更して、プロシージャ showNextMonth を再度実行してみてください。ちゃんと翌月の数字が表示されますよ。引数を持つFunctionプロシージャは、柔軟な使い方ができます。
正解例をもう一つ紹介しておきましょう。
Sub showNextMonth() Range("C5").Value = getNextMonth(Range("C4").Value) End Sub
Functionプロシージャの引数に、ずばりセルC4の値を設定しています。これもOKです。1行で済んでしまいましたね。
コーディングのスタイルは色々あります。自分の思う通りに書いてください。経験とともにスタイルは変化していきます。そうやって分かりやすいコーディングが身についていきます。他人のコードも参考になります。やがていろんなことに気付くようになります。自分なりのよりよいスタイルを築いていってください。
少し話がそれますが、この記事も、僕のスタイルが出ています。ですから、他の方が書いた解説もぜひ読んでください。アプローチの仕方や視点が異なっているはずです。同じことを説明していても、表現が違ってきます。多面的に捉えることができるので、勉強になると思います。
さて、話をもとに戻します。Functionプロシージャの構文は、グレードアップしてこうなりました。
Function 関数名(仮引数名 As データ型) As データ型
借り引数を使って、戻り値を求めるために必要な処理をおこなう
関数名 = 戻り値
End Function
Functionプロシージャを覚えると、Subプロシージャのことも分かってきます。戻り値のないプロシージャがSubプロシージャということになりますね。つまり、Subプロシージャは処理をするだけなのです。