検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-07
要点 — Function は 値を返す プロシージャです。値は関数の 名前そのもの に代入して返します——VBA に Return キーワードはありません。そして値を返すからこそ、ワークシートのセルに自作の数式(UDF)として直接入力できます。
Function AddTax(price As Double, rate As Double) As Double
AddTax = price * (1 + rate) ' 名前に代入する ——これが戻り値
End Function
セルに: =AddTax(A2, 0.2) ' SUM や XLOOKUP の隣に並ぶ、あなた専用の数式
この 「セルの中で生きられる」 という一点こそ、Sub とは別に Function が存在する理由のすべてです。以下はそこから組み立てます。
メンタルモデル:Function は「報告して戻る Sub」
Sub は、作業をして去っていく作業員です。Function は、作業をしてから答えを教えてくれる作業員。 仕組みは同じ——名前つきのコードのかたまりに引数が入る——で、一点だけ違う。値が 出てくる のです。
この出力があるおかげで、Sub には決してできない場所、すなわち ワークシートのセル で Function を使えます。Excel のグリッドは式の結果を表示するためのものなので、値を返すもの——SUM、XLOOKUP、あなたの AddTax——はセルに入れられます。Sub は何も返さず、Excel はセルに入れる物を持てません。=Greet() と入力すれば #NAME? が返ります。この絵を覚えておけば、Sub と Function の選択は自ずと決まります。
たった一つのルール:戻り値は名前に代入する(Return ではない)
Python・JavaScript・C# から来た人を必ず捕まえるバグです。
Function Discount(price As Double) As Double
Discount = price * 0.9 ' ✅ VBA は関数名への代入で値を返す
End Function
Function Broken(price As Double) As Double
Return price * 0.9 ' ❌ VBA はこう動かない ——黙って 0 を返す
End Function
Return は VBA にも存在しますが、古い GoSub の相方としてだけで、値は 返しません。Return と書いても(あるいは名前への代入を丸ごと忘れても)、関数はエラーなくコンパイルされ、その型の既定値——0、""、Empty——を黙って返します。エラーは出ず、結果だけ間違う。UDF がいつも 0 を返すなら、ほぼ確実に名前への代入を忘れています。
名前へは何度代入しても構いません(関数内では普通の変数です)。関数が終わる時点で持っている値が返ります。
Function Grade(score As Long) As String
Grade = "不合格" ' 既定
If score >= 50 Then Grade = "合格"
If score >= 80 Then Grade = "優秀"
End Function
Sub と Function —— 一行で決める
長い比較表は忘れてください。選択は一つの問いに尽きます。
呼ぶ側が答えを必要とするか? はい →
Function。いいえ →Sub。
| Sub | Function | |
|---|---|---|
| 値を返す | いいえ | はい(名前に代入) |
| セルで使える | いいえ | はい(UDF になる) |
| マクロ一覧(Alt+F8)に出る | Public かつ引数なしなら出る | 出ない |
| 典型的な仕事 | 何かを する(書式・出力・削除) | 何かを 計算する(税率・ラベル・整形済み文字列) |
見分けるコツ:Sub に結果をグローバル変数へ押し込ませて別のプロシージャに読ませているなら、本当は Function が欲しかったのです。グローバルでこっそり渡さず、値をきちんと返しましょう。
ワークシート関数(UDF)にする —— 決め手の機能
Function を 標準モジュール([挿入] → [標準モジュール]。シートや ThisWorkbook のモジュール ではない)に置くと、即座にグリッドと数式オートコンプリートで使えるようになります。
Function InitialsOf(fullName As String) As String
Dim parts() As String
parts = Split(Trim(fullName), " ")
InitialsOf = Left(parts(0), 1) & Left(parts(UBound(parts)), 1)
End Function
=InitialsOf("Ada Lovelace") → "AL"
ここで VBA は、周囲の非プログラマーに対して真価を発揮します。ロジックを一度書けば、同僚はコードを見ずに、組み込み関数と同じように使えるのです。
新人 UDF が必ずつまずくルール:ワークシート関数は自分のセルにしか返せない
無数のフォーラム投稿を生む制約がこれです。Function が セルから 呼ばれると、Excel は保護モードで実行し、関数は 何も変更できません——他のセルへの書き込み、色の設定、シート名の変更、MsgBox のいずれも不可。できるのは計算して、呼んだセルの値を返すことだけです。
Function ColorMe(c As Range) As String
c.Interior.Color = vbYellow ' ❌ セルから呼ぶと何もしない
ColorMe = "done"
End Function
これを書いて、文字は出るのに色は付かず、「VBA が壊れている」と結論する人がいます。壊れていません——UDF は設計上「純粋」 です。シートを 変更 したいなら、それは(ボタンやイベントで起動する)Sub の仕事で、UDF の仕事ではありません。この線を知るだけで何時間も節約できます——セルの数式 → 計算して返すだけ。ブックを変える → Sub。
省略可能・型つきの引数で UDF を「ネイティブ」に
二つの工夫で自作関数は使い心地が良くなります。
Function Net(gross As Double, Optional rate As Double = 0.1) As Double
Net = gross / (1 + rate) ' 呼ぶ側が省略すると rate は 0.1
End Function
Optional に既定値を付ければ =Net(A2) も =Net(A2, 0.08) も両方動きます。戻り値の型を Variant のままにせず宣言する(As Double、As String、As Boolean)と、関数は速くなり意図も明確になります。
主張:組み込み関数を作り直さない
VBA の Function は、Excel に まだない ロジックのためのものです。WorksheetFunction.SumIf、TEXTJOIN、XLOOKUP で足りるならそれを呼びましょう——ネイティブ関数は速く、正しく再計算され、マクロ有効ブックも要りません。自作 Function は、本当に固有のルール——自社固有の税率区分、汚い文字列のパーサー、組み込みにない業務計算——に取っておきます。SUM を包むだけの UDF は負債、あなたの業務ルールを表す UDF は資産です。
よくある Function の誤り(と直し方)
| 症状 | 原因 | 直し方 |
|---|---|---|
| 関数がいつも 0 / 空を返す | Return を使った、または名前に代入していない |
結果を関数名に代入:MyFunc = result |
セルが #NAME? |
関数がシートモジュールにある/名前の綴り違い | 標準 モジュール に移す。綴りを確認 |
| UDF がセルの色を変えない | セルから呼ぶ UDF はブックを変更できない | 変更は Sub をボタン/イベントで |
セルが #VALUE! |
関数内の未処理エラー | 入力を検証し、エラーでなく代替値を返す |
| UDF の結果が更新されない | 関数が変更後の入力を見ていない | 変更セルを引数に渡す、または Application.Volatile(控えめに) |
| 呼び出しで「ステートメントの最後が必要です」 | 括弧/Call の混同(Sub と同じ) |
戻り値を使う:x = MyFunc(a) |
数式のロジックそのものが本題なら —— VBA は省こう
自作 Function は、再利用する一つの計算には最適です。けれど作業が「この 2 つのエクスポートを突き合わせ、一致しない行を印付けし、差額を月別に合計する」なら、手で書いて保守したくはありません。ExcelMaster Agent は、その一文を自然な日本語で受け取って結果を出します——デバッグする UDF も、配布するマクロ有効ファイルも不要。無料で試す →
関連記事
- VBA の Sub とは — プロシージャの呼び出し方と「マクロの正体」
- VBA ByRef vs ByVal — 呼び出し後に変数が変わる理由
- VBA MsgBox の使い方 — はい/いいえ・ボタン・括弧ルール
- VBA For ループ — 実務で使う 8 つの例
よくある質問
VBA の Function とは何ですか?
Function は、作業をして呼んだコードに値を返す、名前のついたプロシージャです。Function 名前(引数) As 型 … End Function で定義し、結果を関数の名前そのものに代入して返します。
VBA の関数から値を返すには?
値を関数名に代入します。Function Total() As Double の中で Total = 42 と書きます。VBA にこのための Return 文はありません——Return は古い GoSub のもので、値を返しません。関数が終わる前に名前へ最後に代入した値が返ります。
VBA の関数が 0 や空を返すのはなぜ?
関数名に値を代入していない(または VBA で機能しない Return を使った)からです。関数は型の既定値——0、""、Empty——を返します。End Function の前に 関数名 = 結果 を加えてください。
Excel でユーザー定義関数(UDF)を作るには?
Function を標準モジュール([挿入] → [標準モジュール])に置き、戻り値の型を付けて、結果を名前に代入します。あとはセルで =自作関数(...) と入力します。組み込み関数と同様に数式オートコンプリートに現れます。
UDF が他のセルや色を変えられないのはなぜ?
Excel がセルから Function を呼ぶときは、値を返すことしかできない制限モードで実行されます——ブックの変更(セルへの書き込み、書式、MsgBox)はできません。シートを変えるには、UDF ではなくボタンやイベントで起動する Sub を使います。
Sub ではなく Function を使うのはどんなとき? 呼ぶ側が値を必要とするとき——計算・検索・整形済み文字列——や、セルから呼びたいときは Function を使います。プロシージャが何かを する だけ(書式・出力・削除)で何も返さないなら Sub を使います。
