Excel VBA > Excel上級:マクロ > Functionプロシージャの使い方について考える
このエントリーをはてなブックマークに追加

Functionプロシージャの使い方について考える

FunctionとSubの違いとは

先日、Functionプロシージャの使い方が分からない方から質問を受けました。
その時に「FunctionプロシージャとSubプロシージャは何が違うのか」というものでした。
ただ、話を詰めていくと「Functionプロシージャはどんなときに使うのか知りたい」というものでした。
この質問の回答はVBAに慣れている人と慣れていない人では理解度が違うため、いくつか工夫が必要になりました。

FunctionをSubプロシージャと比較しないほうが分かりやすい時もある

自身でエディタ画面を使って、Subプロシージャを(マクロ記録を使わずに)コードから作成できる人にとっては、Subとの違いを相対的に説明すれば分かるかもしれませんが、本を見ながら何とかSubを作れる人にとっては、あえて比較するとむしろ混乱するのではないかと思いました。
ネットで見れるFunctionも通常はSubプロシージャからFunctionをコールして説明しているサイトを見ますが、これはSubを一通り理解している人向けだと思います。

Subプロシージャと混乱しがちな部分

私自身の経験としても、混乱していた部分ですが、よく一般的には「Subプロシージャは値を返さない」、「Functionプロシージャは値を返す」という説明があります。
■SubとFunctionの連携で値をやり取り

‘======================================
‘Subプロシージャ
‘======================================
Sub テスト()

    Dim str As String

    ‘Functionプロシージャをコールして値を受け取る
    str = テストの結果

    MsgBox str, vbInformation

End Sub

‘======================================
‘Functionプロシージャ
‘======================================
Function テストの結果()

    テストの結果 = “上手くいきました”

End Function

上記でSubプロシージャの「テスト」を実行するとFunctionプロシージャの「テストの結果」が呼び出され値を返します。
要は先ほどの説明通りで、「Subプロシージャは値を返さない」、「Functionプロシージャは値を返す」というわけです。
ただし、これも先ほど話した通り、VBA全般やSubを理解していればわかるかもしれませんが、そうでない場合「分かったような、分かってないような・・」という感じの人もいるかと思いますがいかがでしょうか?

Functionプロシージャでなくとも値が返せる方法がある

実はFunction以外にも値を返す方法があります。厳密には「返す」という表現は当てはまらないかもしれませんが、同じような方法があります。ここがFunctionの分かりにくい部分の一つだと思います。

■方法1:(グローバル)変数を使う
これはグローバルでなくても、モジュールレベルの変数でも可能です。
以下の方法だと値を返すFunctionプロシージャを必要としません。
モジュール先頭に変数を宣言すれば、上記のプロシージャの例と同じように変数strに同じ値が格納されます。

Option Explicit
Dim str As String

‘======================================
‘Subプロシージャ
‘======================================
Sub テスト()

    ‘Subプロシージャをコールして、変数strに値を入れる
    Call テストの結果

    MsgBox str, vbInformation

End Sub

‘======================================
‘FunctionプロシージャをSubに変更
‘======================================
Sub テストの結果()

    str = “上手くいきました”

End Sub

■方法2:値参照でプロシージャをコールする
この方法は「Sub テスト結果」プロシージャをコールするときに引数として変数strを渡します。詳しい説明は省略しますが、この方法でも「SubとFunctionの連携で値をやり取り」の例と同じメッセージボックスが表示されます。

‘======================================
‘Subプロシージャ
‘======================================
Sub テスト()

    Dim str As String

    ‘Subプロシージャをコールして、引数にstrを入れる
    Call テストの結果(str)

    MsgBox str, vbInformation

End Sub

‘======================================
‘FunctionプロシージャをSubに変更
‘引数を「値参照」で受け取る
‘======================================
Sub テストの結果(ByRef str As String)

    str = “上手くいきました”

End Sub

このようにFunctionを使わなくても値を使いまわす方法はあり、実際に方法1の「グローバル変数」でのやり取りは、よく見かける方法です。
(この方法は変数の数が増えてくると管理が煩雑になり、混乱しやすいのでおススメしませんが)
個人的にはFunctionを意図的に使うことで「値を返す」ことが明示的にわかりやく、後でプログラム全体を見たときに管理がしやすくなると思います。
いずれにしても、こうしてみると、Subプロシージャを少しだけ分かっている人から見ると、Functionを使う場面が想定しづらくイメージも湧きにくいかもしれません。

FunctionをSUM、IF等の関数と同等として見る

実は、ここからが本題なのですが前段が思いっきり長くなってしまいました(汗)。
「Functionは値を返す」と言う意味で「関数」であると見ることができます。関数とはおなじみのSUMやIF関数です。Functionはそれと同じ意味を持っています。
「SUM関数は指定した範囲の合計」、「IF関数はセルとセルの比較」と言ったように、Functionは自分で好きな機能を作る(実装する)ことができます。
ここでは例として「消費税を求める関数」を作ってみたいと思います。
(Functionを使わなくても、消費税は数式が使えれば簡単に求めることができますが、このことは今は忘れてください)
下記の表の「消費税」の隣セル(C7)のところに自作の独自関数(消費税を求める関数)を入れてみたいと思います。

そして、下記のようにしたいと思います。

消費税を表示するFunctionプロシージャを作る

繰り返しますが、Functionプロシージャは値を返します。この「返す」という仕組みを使って消費税を返します。どこに返すのか?それはセルにです。
最初に「消費税プロシージャ」を見てください。
(※分かりやすく説明するために小数点や変数の型などは一切無視しています)

Function 消費税(金額)

    消費税 = 金額 * 0.05

End Function

消費税を求める式は「金額 × 0.05」ですね。それを上記で言うと1行で、そのまんまです。
これで「消費税を求める関数」が出来上がりました。そして次にそれをExcelのシート上で使ってみたいと思います。

Functionプロシージャを関数として使うと引数の意味が分かる

今回の消費税を求めるプロシージャでは引数「金額」を使いました。この引数の意味も下記の図から感覚的にわかってもらえるかと思いますがいかがでしょうか?

上記のようにFunctionプロシージャの先頭の「プロシージャ名(引数)」がそのまま関数ボックスに表示されます。
そして、通常の関数を使う方法と同様にセルをセットします。

結果は独自で作成したFunctionプロシージャである「消費税」プロシージャが正しく動作しました。

このようにFunctionプロシージャは関数そのものです。これで「値を返す」と言う意味が分かったと思いますがいかがでしょうか?

Functionの「消費税」プロシージャをSubプロシージャから使ってみる

実際にはセルに直接Functionプロシージャを入れるパターンよりもSubプロシージャとの連携で使う方が圧倒的に多いと思います。
そこで、今回を例を実際にSubから読んだときにどのような使い方になるのかを見てください。

‘======================================
‘Subプロシージャ
‘======================================
Sub テスト()

    Dim str As String

    ‘Functionプロシージャをコールして値を受け取る
    str = 消費税(400)

Range(“C6”).Value = str

End Sub

‘======================================
‘Functionプロシージャ
‘======================================
Function 消費税(金額)

    消費税 = 金額 * 0.05

End Function

上記はプログラム上でのやり取りでセルに埋め込むのとは違うため、「=消費税()」の部分を「str = 消費税(400)」で対応しています。
ただし、セルには値が表示されずに、変数strに消費税額が返されます
そこでさらにセルに結果を書き込むように細工しました。
Range(“C6”).Value = str
上記がそれに当たります。

Functionプロシージャが「値を返す」の意味

Functionの「値を返す」意味がこれで分かったでしょうか?
通常はSubプロシージャから色々勉強を始めると思うので、Subが慣れたころからFunctionの習得を始めるといいかもしれません。
頻繁に登場するわけでもないため、慣れるまでが面倒かもしれませんが、使えるようになるとプログラムの可読性(読みやすさ)を考慮して使うのもいいと思います。

ちなみに、Functionを文字通り関数として使う場合は、この独自の関数が記述されているブックを予め起動しておくことが必要です。あるいはアドインやPersonal.xls(b)などに入れておく必要があり、個人で使う分にはまだしも、複数のPC等で使う場合には使い勝手が良いとはいえず注意が必要です。

カテゴリ:Excel上級:マクロ