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