VBA の Function は通常、1つの戻り値を返す 仕様になっています。
しかし、場合によっては 「複数の値を返したい」 というケースがあります。
例えば、
- 数値の計算結果とエラーステータスを返す
- 開始日と終了日を一度に取得する
- 複数のデータを関数から戻す
このような場合、VBA では配列・ユーザー定義型・ByRef引数を使うことで、複数の戻り値を返すことが可能 です。
本記事では、VBA で Function から複数の戻り値を返す方法とその活用例 を詳しく解説します。
Function で複数の戻り値を返す方法
✅ 方法① 配列を返す(戻り値に配列を使用)
✅ 方法② ユーザー定義型を返す(Type を使う)
✅ 方法③ ByRef で複数の引数を更新(関数の引数を ByRef で変更)
・配列を返す(Variant 型)
VBA の Function は 配列を戻り値として返す ことができます。
【例】2つの数値を加算・減算し、結果を配列で返す
Function Calculate(a As Double, b As Double) As Variant
Dim result(1) As Double
 result(0) = a + b ' 加算
 result(1) = a - b ' 減算
 Calculate = result ' 配列を返す
End Function
Sub TestFunction()
Dim results As Variant
 results = Calculate(10, 5)
Debug.Print "加算結果: " & results(0)
 Debug.Print "減算結果: " & results(1)
End Sub
✅ 戻り値の Variant に配列を代入すると、複数の値を返せる!
✅ 結果を results(0), results(1) のように取得!
・ユーザー定義型(Type)を返す
VBA では、Type を使って カスタム型(ユーザー定義型)を作成し、それを戻り値として返す ことができます。
【例】長方形の面積と周囲長を返す
' ユーザー定義型の宣言(モジュールの上部に記述)
 Type RectangleData
Area As Double
 Perimeter As Double
End Type
Function GetRectangleData(width As Double, height As Double) As RectangleData
Dim result As RectangleData
 result.Area = width * height ' 面積
 result.Perimeter = 2 * (width + height) ' 周囲長
 GetRectangleData = result ' ユーザー定義型を返す
End Function
Sub TestRectangle()
Dim rect As RectangleData
 rect = GetRectangleData(10, 5)
Debug.Print "面積: " & rect.Area
 Debug.Print "周囲長: " & rect.Perimeter
End Sub
✅ Type を使うと、関連する複数の値を1つのオブジェクトとして管理できる!
✅ rect.Area や rect.Perimeter のように分かりやすくデータを取得できる!
・ByRef で複数の引数を更新
関数の引数を ByRef で渡すことで、複数の変数の値を関数内で変更し、実質的に複数の戻り値を持たせる ことができます。
【例】最大値と最小値を取得
Sub GetMinMax(a As Double, b As Double, ByRef minVal As Double, ByRef maxVal As Double)
If a < b Then
minVal = a
 maxVal = b
Else
minVal = b
 maxVal = a
End If
End Sub
Sub TestMinMax()
Dim minVal As Double, maxVal As Double
 GetMinMax 10, 5, minVal, maxVal
Debug.Print "最小値: " & minVal
 Debug.Print "最大値: " & maxVal
End Sub
✅ ByRef を使うと、複数の変数の値を変更できる!
✅ 値を直接変更するため、メモリ効率が良い!
✅ 関数の戻り値が不要なので、可読性が向上!
実際の活用例
【例①】日付の開始日と終了日を取得
Function GetStartEndDate() As Variant
Dim result(1) As Date
 result(0) = DateSerial(2024, 1, 1) ' 開始日
 result(1) = DateSerial(2024, 12, 31) ' 終了日
 GetStartEndDate = result
End Function
Sub TestDateRange()
Dim dates As Variant
 dates = GetStartEndDate()
Debug.Print "開始日: " & dates(0)
 Debug.Print "終了日: " & dates(1)
End Sub
✅ 開始日・終了日を一度に取得!
【例②】エラーコードとメッセージを返す
Type ErrorInfo
Code As Integer
 Message As String
End Type
Function ValidateNumber(n As Double) As ErrorInfo
Dim err As ErrorInfo
 If n < 0 Then
err.Code = 1
 err.Message = "負の数は許可されていません"
Else
err.Code = 0
 err.Message = "OK"
End If
ValidateNumber = err
End Function
Sub TestError()
Dim result As ErrorInfo
 result = ValidateNumber(-10)
Debug.Print "エラーコード: " & result.Code
 Debug.Print "メッセージ: " & result.Message
End Sub
✅ エラーコードとメッセージをセットで返せる!
どの方法を選ぶべきか?
| 方法 | メリット | デメリット | おすすめの用途 | 
|---|---|---|---|
| 配列を返す | 簡単に複数の値を返せる | 配列の意味が分かりづらい | シンプルな数値処理 | 
| ユーザー定義型を返す | 値の意味を明確にできる | Typeの定義が必要 | 複数の関連データを扱う場合 | 
| ByRef で更新 | メモリ効率が良い | 呼び出し側で変数を用意する必要あり | 複数の変数を直接変更したい場合 | 
まとめ
| 方法 | 適した用途 | 
|---|---|
| 配列を返す | シンプルな数値や日付のセットを返す | 
| ユーザー定義型を返す | 意味のある複数のデータを返す | 
| ByRef で更新 | メモリ効率を重視し、変数を直接変更したい |