Excel VBA | 安全に ByRef を使う設計パターン(コード例付き)

VBA
スポンサーリンク

ByRef は「呼び出し元の変数を直接書き換える」ため便利ですが、初心者が使うと副作用で混乱しやすいです。そこで 安全に使うための設計パターン をコード例付きで整理します。


1. 複数値返却パターン

目的

関数の戻り値は1つしか返せないため、複数の結果を返したいときに ByRef を使う。

コード例

Sub GetCoordinates(ByRef x As Double, ByRef y As Double)
    x = 10
    y = 20
End Sub

Sub TestCoordinates()
    Dim a As Double, b As Double
    GetCoordinates a, b
    Debug.Print a, b   ' → 10, 20
End Sub
VB

ポイント

  • 戻り値では1つしか返せない → 複数値返却に ByRef が便利。
  • 引数名を「返却用」と分かるようにする(例: ByRef resultX)。

2. 参照差し替えパターン

目的

呼び出し元の変数が指すオブジェクトや範囲を、意図的に別のものへ差し替える。

コード例

Sub MoveRange(ByRef r As Range)
    Set r = r.Offset(1, 0)   ' 呼び出し元も次の行を指すようになる
End Sub

Sub TestMoveRange()
    Dim rng As Range
    Set rng = Sheet1.Range("A1")
    MoveRange rng
    rng.Value = "Shifted"    ' A2 に書き込まれる
End Sub
VB

ポイント

  • 「参照を差し替える」意図を明示する。
  • コメント必須:「このSubは参照を変更します」。

3. 戻り値+ByRefの役割分担

目的

  • 主結果は戻り値で返す
  • 副次結果は ByRef で返す

コード例

Function Divide(ByVal a As Double, ByVal b As Double, ByRef remainder As Double) As Double
    remainder = a Mod b
    Divide = a \ b
End Function

Sub TestDivide()
    Dim q As Double, r As Double
    q = Divide(10, 3, r)
    Debug.Print q   ' → 3
    Debug.Print r   ' → 1
End Sub
VB

ポイント

  • 主結果は戻り値 → 読みやすい。
  • 副次結果は ByRef → 複数返却が必要な場合に限定。

4. ByRef を「返却専用」にする

目的

入力は壊さず、出力専用の引数だけ ByRef にする。

コード例

Sub CalculateStats(ByVal arr() As Double, ByRef avg As Double, ByRef maxVal As Double)
    Dim i As Long, sum As Double
    sum = 0
    maxVal = arr(LBound(arr))
    
    For i = LBound(arr) To UBound(arr)
        sum = sum + arr(i)
        If arr(i) > maxVal Then maxVal = arr(i)
    Next
    
    avg = sum / (UBound(arr) - LBound(arr) + 1)
End Sub

Sub TestStats()
    Dim data(1 To 3) As Double
    Dim avg As Double, maxVal As Double
    
    data(1) = 10: data(2) = 20: data(3) = 30
    CalculateStats data, avg, maxVal
    Debug.Print avg, maxVal   ' → 20, 30
End Sub
VB

ポイント

  • 入力は必ず ByVal
  • 出力専用の引数だけ ByRef
  • 役割を分けることで副作用を防ぐ。

5. 参照破棄を明示的に行う

目的

呼び出し元の参照を意図的に消す(リソース解放)。

コード例

Sub ReleaseRange(ByRef r As Range)
    Set r = Nothing   ' 呼び出し元も参照が消える
End Sub

Sub TestRelease()
    Dim rng As Range
    Set rng = Sheet1.Range("A1")
    ReleaseRange rng
    Debug.Print rng Is Nothing   ' → True
End Sub
VB

ポイント

  • 「このSubを呼ぶと参照が消える」とコメントで明示。
  • 誤用すると Null 参照エラーになるため注意。

✅ 総まとめ

  • 基本は ByVal → 副作用を避ける。
  • ByRef は「返却用」「参照差し替え用」に限定
  • 戻り値と ByRef を使い分ける → 主結果は戻り値、副次結果は ByRef。
  • コメントや名前付けで意図を明示 → 読みやすく安全。
VBA
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました