Excel VBA > Excel上級:マクロ > SubとFunctionで同じプロシージャを作ってみた
このエントリーをはてなブックマークに追加

SubとFunctionで同じプロシージャを作ってみた

SubとFucntionで同じプロシージャを作る

以前Functionの使い方について書きましたが、更に突っ込んでみたいと思います。
下記のように処理内容が同じプログラムを2つ作りました。
1つはSubプロシージャで作り、もう1つはFunctionプロシージャで作りました。

‘———————————————————–
‘Subプロシージャで実行
‘———————————————————–
Sub S_担当者名チェック()

  If Range(“B1”).Value = “” Then
     MsgBox “担当者名が入力されていません”, vbCritical
  End If

End Sub

‘———————————————————–
‘Functionプロシージャで実行
‘———————————————————–
Function F_担当者名チェック()

  If Range(“B1”).Value = “” Then
     MsgBox “担当者名が入力されていません”, vbCritical
  End If

End Function

SubとFunctionの形式的な違い

上記サンプルプログラムでの違いは
・プロシージャ名が違う(VBAの仕様として同じ名前にできない)
くらいで可能な限り同じにしました。

ここではSubとFunctionの違いを説明するだけなので、処理内容は
・セルB1が空白ならエラーメッセージを表示する
というシンプルなプログラムを作りました。

SubとFucntionで何が変わるのか

さて、ここから本題です。では上記の2つのVBAのプロシージャのどちらを使うことが望ましいのでしょうか?あるいはどちらでも良いのでしょうか?
私の回答は「どちらかと言えばSub」ですが、利用する状況によってSubまたはFunctionを使い分けるでしょう。

この点はプログラムを始めた方など悩むところのようです。
プログラム的に言えば、どちらも正しく機能するため機械的にどちらか一方と言う決め方もできませんから尚のことかもしれません。
ただ、どちらでも良いという回答だけでは中途半端なのでもう少し踏み込んでみたいと思います。

プロシージャの役割

このあたりになると開発者の考え方やスキルに依存する部分も大きくなるため、「一概には言えない」という部分を含んでみてもらいですが、SubとFunctionではそれぞれ機能的な役割があります。
簡単にいうと「Subは、単独で実行できる」、「Functionは、呼ばれて動く」という役割があります。
簡単な例では「マクロの実行画面」で分かります。

上記のようにSubで作ったプロシージャはここから実行できますが、Functionで作ったプロシージャはここからは実行できません。これはシンプルですが大きな違いですね。
また、例えば次ような使い方をする場合はFunctionではできません。
シート上に画像や図形を置き、それをクリックすると作ったマクロが実行される場合です。

一方、Functionを単体でこの場合で使うにはシート(セル)に埋め込む方法があります。
(ただしこの方法は[本来の使い方とはやや異なる点もあり]無限ループに近い形でメッセージが表示されますので注意してください)

Functionは引数が必要であるべき!?

Functionは「関数」です。Sum関数やIF関数と同じ関数です。関数は通常は「引数」を必要とします。サンプルではSubと極力同じ形にするため、引数を入れていませんが通常は引数を使います。というより引数を使うことでメリットが出ると思います。
更に通常は、そのFunctionが返す値の型も決めますが、この辺は使い慣れてこないと分かりづらいかもしれませんが、引数がないと処理が限定されてしまいFunctionである意味がなくなる(→Subでいい)場合もあります。
引数があったほうが良いということは、つまりFunction単独で実行しないことが前提になります。逆に言うと、単独で実行する場合にはSubの方が良いということでもあります。

Functionが役に立つ場合

これも人によってマチマチの回答がありそうですが、通常はFunctionはシートに埋め込んで使うよりも、プログラムとプログラムの連携で使うことでメリットがあると思います。
これも逆に見ると、1つのプロシージャで処理を全て終わらすとFunctionは不要になり、Subで事足りるということになります。

では連携とはどういうことかというとイメージとしては下記の形です。

‘———————————————————–
‘Subプロシージャで実行
‘———————————————————–
Sub S_担当者名チェック()

  If F_担当者名チェック(Range(“B2”)) = False Then
     MsgBox “担当者名が入力されていません”, vbCritical
  End If

End Sub

‘———————————————————–
‘Subからコールされて実行
‘———————————————————–
Function F_担当者名チェック(Rng As Range) As Boolean

  If Rng.Value = “” Then
     F_担当者名チェック = False
  Else
     F_担当者名チェック = True
End If

End Function

例えば、上記のようにメインとなるSubプロシージャ「S_担当者名チェック」からFunctionプロシージャの「F_担当者名チェック」を呼び出して実行し、セルに値が入っているかどうかのみを判定し、その判定結果をSubプロシージャに返します。
イメージとして言えば、Subが親であり、Functionは子です。
こうすることでSub側で判定結果を判別し、その結果に沿ったメッセージを表示するという方法です。
(ここは説明が難しいところですが)
このようにFunctionでは「値の判定まで」を行うことで、それ以降の処理をどうするかはSub(親)側で決めることができるので、制御を1つのプロシージャの中で管理することが可能です。

最初に提示したSubとFunctionは同じプロシージャですが、そもそも「この処理でどんなメリットがあるか」ということ自体が無意味に思えるようになると、それは1つ上のステップに上がったと言えるかもしれません。

参考:いや、ここはSubじゃない・・「Functionだ!」と感じるとき(をゆるく説明します)

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