Excel VBA | ByRef の動きをステップ実行で確認するレッスン

VBA
スポンサーリンク

「ByRefは呼び出し元の変数そのものを参照する」という感覚を、ステップ実行で体験しながら掴みます。止める位置、見るべき値、起こる変化を順に確認していきます。


準備と基本コード

Sub Lesson_ByRef()
    Dim a As Long, b As Long
    a = 10: b = 3

    Adjust a, b            ' ← この行が「呼び出し」。ByRefの効果がここから始まる
    Debug.Print "a=" & a, "b=" & b
End Sub

Sub Adjust(ByRef x As Long, ByVal y As Long)
    x = x + y              ' ← ByRef の本丸。ここで呼び出し元 a が更新される
End Sub
VB
  • 狙い: Adjust内の代入が呼び出し元に波及する瞬間を、F8のステップとウォッチで可視化する。

レッスン1 呼び出し元から入り、ByRefの参照を体験

  1. ブレークポイントを設定:
    • Adjust a, b の行と、x = x + y の行に置く(左余白クリック or F9)。
  2. Mainを開始:
    • Lesson_ByRef を実行。呼び出し行で停止。
  3. ステップイン(F8)で関数へ入る:
    • Adjust内に移動。ローカルウィンドウで値を確認。
    • 停止直後の値は「x = 10」「y = 3」になっているはず。
  4. 代入行をF8で実行:
    • 実行直後、ローカルで x = 13 に変化。
  5. ステップアウト(Ctrl+Shift+F8)で戻る:
    • 呼び出し元へ復帰後、イミディエイトで ? a, b を確認。
    • a = 13b = 3(bはByValなので不変)。
  • ポイント:
    • ByRefは別名: xはaの“別名”。xの更新は即ちaの更新。
    • ByValはコピー: yはbの“値のコピー”。更新してもbは変わらない。

レッスン2 「途中で書き換え」を見抜くウォッチ設定

Sub Sneaky()
    Dim a As Long, b As Long
    a = 5: b = 2
    Adjust a, b            ' ここで a が 7 になるはず
    Overwrite a            ' ここで a を別の値に上書き
    Debug.Print "a=" & a, "b=" & b
End Sub

Sub Overwrite(ByRef z As Long)
    z = 100                ' ← ByRef経由で呼び出し元の a を上書き
End Sub
VB
  • ウォッチ登録:
    • a を「式の内容が変化したときに中断」でウォッチ。
  • 実行観察:
    • Adjustの実行後に a が 7 へ変化した瞬間で停止。
    • Overwriteで a が 100 に変化した瞬間でも停止。
  • 狙い: どの行が、いつ、呼び出し元を書き換えたかを“自動停止”で確定させる。

レッスン3 複合型(配列やオブジェクト)のByRefを実感

配列(要素更新の波及)

Sub Lesson_Array()
    Dim arr() As Long
    ReDim arr(0 To 2)
    arr(0) = 10: arr(1) = 20: arr(2) = 30

    BumpFirst arr           ' ← 配列をByRefで渡す(既定はByRef)
    Debug.Print arr(0), arr(1), arr(2)
End Sub

Sub BumpFirst(ByRef a() As Long)
    a(0) = a(0) + 1         ' ← 呼び出し元の配列要素が直接変わる
End Sub
VB
  • 観察:
    • BumpFirst内で停止して a(0)11 に。戻ると arr(0)11
  • ポイント:
    • 配列は参照性が強く、ByRefで「中身の更新が呼び出し元へ直結」する。

オブジェクト(Range/Collection)の操作

Sub Lesson_Object()
    Dim c As Collection
    Set c = New Collection
    c.Add "A": c.Add "B"

    AddC c                  ' 要素数が呼び出し元でも増える
    Debug.Print c.Count     ' → 3
End Sub

Sub AddC(ByRef col As Collection)
    col.Add "C"             ' ← col は c の参照。中身が増える
End Sub
VB
  • 観察:
    • AddC後に c.Count3。内部操作が即呼び出し元へ反映。

レッスン4 ByValとの違いを数秒で納得

Sub Contrast()
    Dim a As Long, b As Long
    a = 10: b = 3

    Adjust_Val a, b         ' ByVal で渡すと…
    Debug.Print "a=" & a, "b=" & b
End Sub

Sub Adjust_Val(ByVal x As Long, ByVal y As Long)
    x = x + y               ' ← x は「コピー」。呼び出し元 a は変わらない
End Sub
VB
  • 観察:
    • 関数内では x=13 になるが、戻ると a=10 のまま。
  • 結論:
    • 外を変えたいなら ByRef、内部だけで使うなら ByVal

つまずき対策のチェックリスト

  • 止まらない:
    • ブレーク行が通っていない。 条件分岐の外や早期Exitの手前に置いていないか確認。
  • ウォッチが見えない:
    • コンテキスト不一致。 ウォッチの「現在のプロシージャ」を調整。
  • 副作用が多すぎる:
    • 変化で中断が連発。 一時的に無効化、または「式が真のとき」で条件を絞る。

まとめの指針

  • 副作用を見るならByRefの代入行にブレークポイント。
  • 呼び出し前後で値をイミディエイト/ローカルで確認。
  • “いつ変わったか”はウォッチの「変化で中断」で自動検出。
VBA
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました