【VBA】Functionプロシージャの使い方|Subとの違いと呼び出し方

【VBA】Functionプロシージャの使い方|Subとの違いと呼び出し方

Functionプロシージャって、Subと何が違うの?

他の言語みたいにReturnって書いたら、エラーになったんだけど…

VBAのプロシージャで主に使うのは SubとFunctionの2種類 です。
ざっくり言うと、Functionは「値を返せる処理」 です。

ただ、このFunctionプロシージャ、他の言語を触ったことがある人ほど戸惑いやすいんですよね。
Return が使えなかったり、呼び出すときのカッコの有無で挙動が変わったり。

この記事では、Functionプロシージャの書き方と呼び出し方を、つまずきやすいポイントごとに整理していきます。

この記事でわかること
  • FunctionプロシージャとSubプロシージャの違い
  • 戻り値の書き方と、VBAにReturnがない理由
  • カッコの有無で変わる呼び出し方の使い分け
  • Excelのワークシート関数(ユーザー定義関数)としての使い方

なお、そもそも「引数」「戻り値」がピンとこないという方は、先にこちらをどうぞ。

この記事は、Microsoft 365版のExcel(Windows)に搭載されているVBAを前提にしています(2026年8月時点)。
Excel 2019 / 2021でも、ここで扱う範囲の書き方は変わりません。

Functionプロシージャとは?Subプロシージャとの違い

Functionプロシージャとは、処理をしたあとに呼び出し元へ値を返せるプロシージャのことです。

VBAで基本になるプロシージャは Sub 〜 End Sub と Function 〜 End Function の2つです。
(クラスモジュールで使う Property プロシージャもありますが、入門段階では意識しなくて大丈夫です)

そしてこの2つの違いは、「値を返せるかどうか」だけ と言ってもいいくらいシンプルです。

プロシージャ

VBAで書く処理の最小単位のことです。1つのSub、1つのFunctionが、それぞれ1プロシージャにあたります。

並べて見るとイメージしやすいと思います。

'// Subプロシージャ:処理をするだけ。値は返せない
Sub ShowHello()
    MsgBox "こんにちは"
End Sub

'// Functionプロシージャ:処理をして、結果を返せる
Function GetHello() As String
    GetHello = "こんにちは"
End Function

ShowHello はメッセージを出して終わり。
GetHello は 「こんにちは」という文字列を呼び出し元に渡して終わり です。

つまり、結果が欲しいならFunction・処理してほしいだけならSub、という住み分けになります。

らるじゅらるじゅ

最初のうちは全部Subで書いてしまいがちなんですよね。
「この処理の結果、あとで使うかも?」と思ったらFunctionにしておくと後がラクです。

プロシージャという単位そのものの位置づけは、こちらで解説しています。

Functionプロシージャの書き方|VBAに「Return」はない

ここが最初の関門です。
Java・Python・JavaScriptなどを触ったことがある人ほど引っかかるので、順番に見ていきます。

基本の形|戻り値はプロシージャ名に代入する

VBAでは、プロシージャ名そのものに値を代入することで戻り値を設定します。

Function AddNumbers(ByVal numA As Long, ByVal numB As Long) As Long

    '// プロシージャ名に代入した値が、そのまま戻り値になる
    AddNumbers = numA + numB

End Function

Subとの書き方の違いは1箇所だけです。
() のうしろに As 型 を付けて、戻り値の型を宣言する。ここだけが増えます。

引数の書き方(() の中に「変数名 As 型」、複数ならカンマ区切り)はSubとまったく同じなので、Subが書ければFunctionもすぐにOKです。

なお As Long の部分は省略もできますが、省略すると戻り値はなんでも入るVariant型になります。
型が曖昧なままだと思わぬ挙動の原因になるので、戻り値の型は必ず書くのがおすすめです。

他の言語の「Return」にあたる書き方

多くの言語では return numA + numB のように書きますが、VBAではこの書き方はできません。

Function AddNumbers(ByVal numA As Long, ByVal numB As Long) As Long

    '// これはコンパイルエラーになる
    Return numA + numB

End Function

VBAにも Return というキーワード自体は存在します。
ただしそれは GoSub で飛んだ先から戻ってくるための命令であって、戻り値を返すためのものではありません。そのため Return 値 と書くとコンパイルエラーになります。

VBAの戻り値は returnで返すのではなく、プロシージャ名に入れておく イメージ。
「代入した値が、そのまま持ち帰られる」と考えると迷いにくくなります。

途中で処理を抜けるなら Exit Function

「条件を満たしたら、そこで終わらせたい」というケースもあります。
その場合は Exit Function を使います。

Function SafeDivide(ByVal numA As Double, ByVal numB As Double) As Double

    '// 0で割ろうとしたら、0を返して終了する
    If numB = 0 Then
        SafeDivide = 0
        Exit Function
    End If

    SafeDivide = numA / numB

End Function

ポイントは、Exit Function は「抜ける」だけで、値を返す機能はないということ。
抜ける前にプロシージャ名へ代入しておかないと、戻り値は型ごとの初期値(数値なら0、文字列なら空文字)のままになります。

ありがちなミス

Exit Function の前に代入を書き忘れて、どの条件でも0が返ってくるという不具合。
Functionを書いたら「どのルートを通っても代入されているか」を確認するクセをつけておくと安心です。

Functionプロシージャの呼び出し方|カッコの有無で挙動が変わる

書けるようになったら、次は呼び出し方です。
VBAはカッコのルールが独特なので、ここを押さえるとエラーで悩む時間がかなり減ります。

1. 戻り値を変数で受け取る

いちばん基本の形です。戻り値を使うときは、引数を必ずカッコで囲みます。

Sub Test1()

    Dim result As Long

    result = AddNumbers(10, 20)    '// resultに30が入る

    Debug.Print result

End Sub

2. 式や他の関数の中でそのまま使う

変数に入れずに、値そのものとして使うこともできます。

Sub Test2()

    MsgBox AddNumbers(10, 20)             '// 30と表示される
    Debug.Print AddNumbers(1, 2) * 100    '// 300と表示される

End Sub

Functionは「実行するもの」というより 「値そのもの」として扱える と考えると、書ける場所のイメージがつきやすいです。

3. 戻り値を使わずに呼ぶ

Functionは、戻り値を受け取らずに呼ぶこともできます。
その場合の書き方は2通りあります。

Sub Test3()

    Call AddNumbers(10, 20)    '// Callを使う場合はカッコが必要
    AddNumbers 10, 20          '// Callを省略する場合はカッコなし

End Sub

3つの呼び方を整理すると、次のようになります。

書き方カッコ戻り値
result = AddNumbers(10, 20)必要受け取る
Call AddNumbers(10, 20)必要捨てる
AddNumbers 10, 20不要捨てる

Call は省略できますが、「これはプロシージャの呼び出しだ」と一目で分かるので、書いておくほうが読みやすいと思います。

つまずきやすい「カッコの罠」

最後に、初心者がハマりやすいポイントを1つ。
引数が1つのときにCallなしでカッコを付けると、意味が変わってしまうことがあります。

この挙動はSubでもFunctionでも同じなので、変化が見えやすいSubの例で確認してみます。

Sub AddSuffix(ByRef target As String)
    target = target & "さん"
End Sub

Sub Test4()

    Dim name1 As String
    name1 = "らるじゅ"
    Call AddSuffix(name1)
    Debug.Print name1        '// らるじゅさん

    Dim name2 As String
    name2 = "らるじゅ"
    AddSuffix (name2)        '// カッコが「式」として解釈される
    Debug.Print name2        '// らるじゅ(変わらない!)

End Sub

Call なしでカッコを付けると、VBAはカッコの中を「計算する式」として先に評価します。
その結果、参照渡し(ByRef)で書いたはずなのに 値渡しとして扱われ、呼び出し元の変数が変わらない という現象が起きます。

対策はシンプルで、Callなしでカッコを付ける書き方をしないこと。
先ほどの表にある3パターンだけを使っていれば、この罠を踏むことはありません。

参照渡し(ByRef)と値渡し(ByVal)の違いが曖昧な場合は、引数と戻り値の記事を先に読んでおくと理解が早いと思います。

Excelのワークシート関数として使う|ユーザー定義関数(UDF)

Functionプロシージャには、もう1つ大きな役割があります。
それが、Excelのセルで使える「自作の関数」を作れることです。

これを ユーザー定義関数(UDF:User Defined Function) と呼びます。

たとえば、税込金額を計算する関数を作ってみます。

'// 標準モジュールに書く
Public Function 税込(ByVal price As Double, ByVal rate As Double) As Double
    税込 = price * (1 + rate)
End Function

これを標準モジュールに書いておくと、シート上で =税込(A1, 0.1) のように使えます。

SUM関数やIF関数と同じ感覚で、自分専用の関数が作れるわけです。
長い数式を何度もコピーしている作業があるなら、UDFにまとめてしまうと数式がぐっと読みやすくなります。

ユーザー定義関数の良いところ
  • 長い数式を関数名ひとつにまとめられる
  • 修正はVBA側の1箇所だけで済む
  • 数式の意味が名前から伝わるので、他の人が読みやすい
ユーザー定義関数の制約
  • 標準モジュールに書かないとセルから呼び出せない(シートモジュール・ThisWorkbookはNG)
  • Private を付けると数式から使えない(#NAME? になる)
  • セルの値や書式を変更する処理を書いても反映されない(値を返すことしかできない)
  • 保存するときは マクロ有効ブック(.xlsm) にする必要がある

「セルの値を変えられない」は最初びっくりするところですが、UDFはあくまで値を計算して返す係 と割り切るのが正解です。
セルを書き換えたい処理は、Subプロシージャとして書いてボタンなどから実行しましょう。

自作の関数って作れるんだ…!

なお「標準モジュールって何?」という方は、モジュールの種類をこちらで整理しています。

SubとFunctionの使い分け|迷ったときの判断軸

ここまでの内容を、選び方の視点でまとめます。

観点SubプロシージャFunctionプロシージャ
戻り値× 返せない◎ 返せる
Excelの「マクロ」一覧に表示◎ 表示される× 表示されない
セルの数式から使う× 使えない◎ 使える(標準モジュール)
式の中に書く× 書けない◎ 書ける
向いている処理ファイル操作・印刷・保存など判定・計算・変換など

Excelの「マクロ」ダイアログに出てくるのは、引数のないSubプロシージャだけです。
そのため、ボタンに登録して実行させたい処理はSubで書くことになります。

どっちを使えばいい?
  • 処理の結果(値)を後で使いたい → Functionプロシージャ
  • 画面操作やファイル操作をさせたい → Subプロシージャ
  • セルの数式から呼びたい → Functionプロシージャ(標準モジュールにPublicで)
  • 迷ったら、まずSubで書いて、値が必要になった時点でFunctionに変えるでもOK

なお、Functionプロシージャが返せる戻り値は1つだけです。
複数の値を返したい場合は、引数を参照渡しにする・変数のスコープを広げるといった方法で対応することになります。

まとめ|Functionは値を返す処理、呼び出しはカッコが決め手

今回は、VBAのFunctionプロシージャについて、書き方から呼び出し方までを整理しました。

つまずきやすいのは、結局のところ Returnが使えないこと と カッコのルール の2つだと思います。
ここさえ押さえてしまえば、Functionは処理を部品に分けるための強い味方になります。

この記事のまとめ
  • Functionプロシージャは戻り値を返せるプロシージャ。Subは返せない
  • VBAに戻り値用のReturnはなく、プロシージャ名に代入して返す
  • 途中で抜けるならExit Function。抜ける前に代入しておく
  • 戻り値を使うならカッコあり、使わないならCall+カッコ or カッコなし
  • 標準モジュールにPublicで書けば、セルの数式から使えるユーザー定義関数になる
らるじゅらるじゅ

Functionが書けるようになると処理を部品に分けられるようになって、
コードがぐっと読みやすくなります。一緒に少しずつ進んでいきましょう!