Excel VBA | 参照渡し(ByRef)

VBA
スポンサーリンク

Excel VBA の引数の渡し方の基本

「値渡し(ByVal)」と「参照渡し(ByRef)」は、プロシージャ(SubやFunction)に変数を渡すときの“渡し方”です。ポイントは「呼び出し先で変えた内容が呼び出し元に戻ってくるかどうか」。初心者はここだけ覚えればOKです。


ことばの意味をかみ砕く

  • 値渡し(ByVal)
    • イメージ: 変数の“コピー”を渡す。
    • 結果: 呼び出し先で値を変えても、元の変数は変わらない。
    • 使いどころ: 安全に渡したい、勝手に書き換えられたくないとき。
  • 参照渡し(ByRef)
    • イメージ: 変数の“本体”を渡す。
    • 結果: 呼び出し先で値を変えると、元の変数も変わる。
    • 使いどころ: 呼び出し先で結果を作って、そのまま呼び出し元に反映させたいとき。
  • 補足(VBAのデフォルト)
    • 基本: 引数は指定しないとByRef(参照渡し)になります。変えられたくないなら、明示的にByValを書く癖を付けると安全です。

まずは超シンプルな例

数値の例(ByVal vs ByRef)

Sub TestByVal()
    Dim x As Integer
    x = 5
    Call AddTenByVal(x)   ' ← 値渡し
    Debug.Print x         ' 結果:5(変わらない)
End Sub

Sub AddTenByVal(ByVal n As Integer)
    n = n + 10
End Sub
VB
Sub TestByRef()
    Dim x As Integer
    x = 5
    Call AddTenByRef(x)   ' ← 参照渡し
    Debug.Print x         ' 結果:15(変わる)
End Sub

Sub AddTenByRef(ByRef n As Integer)
    n = n + 10
End Sub
VB
  • ポイント:
    • ByVal: 「コピー」を10増やしても、元のxはそのまま。
    • ByRef: 「本体」を10増やすので、元のxが書き換わる。

文字列の例と「呼び出し元に返したい」場面

文字列をくっつける(ByRefで結果を返す)

Sub MakeGreeting()
    Dim msg As String
    msg = "こんにちは"
    Call AppendEvening(msg)    ' ByRef で結果を“直接”反映
    Range("A1").Value = msg    ' → 「こんにちは、こんばんは」
End Sub

Sub AppendEvening(ByRef s As String)
    s = s & "、こんばんは"
End Sub
VB
  • ポイント:
    • 目的が「結果を作って返す」ならByRefがシンプル。
    • 関数の戻り値を使ってもOKだけど、複数の値を返したいときはByRefが便利。

関数での使い分けと安全対策

関数の戻り値を使う(副作用なしでわかりやすい)

Sub UseFunctionSafely()
    Dim price As Double
    price = 1000
    Range("A1").Value = AddTax(price)   ' 1100 を表示
    Debug.Print price                    ' 1000(元の値は変わらない)
End Sub

Function AddTax(ByVal amount As Double) As Double
    AddTax = amount * 1.1
End Function
VB
  • ポイント:
    • 安全に計算したいなら引数はByVal+戻り値で返す。
    • 「元の変数を変えたい」明確な意図があるときだけByRef。

ありがちな落とし穴と回避法

  • デフォルトがByRef問題
    • 落とし穴: 引数にByValを付け忘れると、意図せず元の変数が書き換わる。
    • 回避: 「基本はByVal、書き換えたいときだけByRef」が安全な習慣。
  • コレクションやオブジェクト
    • 性質: オブジェクト変数(Range、Collectionなど)はByValでも“参照のコピー”が渡るため、内部の状態変更は呼び出し元に影響しがち。
    • 回避: 「オブジェクトを丸ごと変更する処理」は慎重に。必要なら新しいオブジェクトを作って返す。
  • 読みやすさ(チーム開発でも安心)
    • コツ: 「変更を狙う引数はByRef」「それ以外はByVal」とルール化すると、コードの意図が伝わりやすくなる。

練習問題(手で動かして違いを体感)

  • 課題1:数値の更新
    • やること: 変数xを20にして、ByValで10足すSubと、ByRefで10足すSubをそれぞれ呼び出し、結果の違いをDebug.Printで確認。
    • 狙い: ByValは元のxが変わらず、ByRefは変わることを確認。
  • 課題2:二つの値を返す
    • やること: 引数を二つ(ByRef a, ByRef b)にして、aに「こんにちは」、bに「こんばんは」を入れて返すSubを作る。
    • 狙い: 複数の結果を返したいときにByRefが便利なことを体験。
  • 課題3:安全な関数設計
    • やること: 金額に割引を適用するFunctionを作り、引数はByVal、戻り値で結果を返す。元の金額が変わらないことを確認。
    • 狙い: 「副作用なし」の設計感覚を身につける。

解答と解説

練習問題1:数値の更新

問題:
変数 x を 20 にして、ByVal で 10 足す Sub と、ByRef で 10 足す Sub を呼び出し、結果の違いを確認。

解答コード:

Sub TestByVal()
    Dim x As Integer
    x = 20
    AddTenByVal x
    Debug.Print x   ' 結果:20
End Sub

Sub AddTenByVal(ByVal n As Integer)
    n = n + 10
End Sub


Sub TestByRef()
    Dim x As Integer
    x = 20
    AddTenByRef x
    Debug.Print x   ' 結果:30
End Sub

Sub AddTenByRef(ByRef n As Integer)
    n = n + 10
End Sub
VB

解説:

  • ByVal → コピーを渡すので、呼び出し先で n を 30 にしても元の x は 20 のまま。
  • ByRef → 本体を渡すので、呼び出し先で n を 30 にすると元の x も 30 に変わる。

練習問題2:二つの値を返す

問題:
引数を二つ(ByRef a, ByRef b)にして、a に「こんにちは」、b に「こんばんは」を入れて返す Sub を作る。

解答コード:

Sub TestGreeting()
    Dim msg1 As String, msg2 As String
    SetGreeting msg1, msg2
    Debug.Print msg1   ' 結果:「こんにちは」
    Debug.Print msg2   ' 結果:「こんばんは」
End Sub

Sub SetGreeting(ByRef a As String, ByRef b As String)
    a = "こんにちは"
    b = "こんばんは"
End Sub
VB

解説:

  • Sub の中で ab に文字列を代入すると、呼び出し元の msg1msg2 にそのまま反映される。
  • 複数の値を返したいときは ByRef が便利。関数の戻り値は1つしか返せないので、こういう場面で役立つ。

練習問題3:安全な関数設計

問題:
金額に割引を適用する Function を作り、引数は ByVal、戻り値で結果を返す。元の金額が変わらないことを確認。

解答コード:

Sub TestDiscount()
    Dim price As Double
    price = 1000
    Debug.Print ApplyDiscount(price)   ' 結果:800
    Debug.Print price                  ' 結果:1000(元の値は変わらない)
End Sub

Function ApplyDiscount(ByVal amount As Double) As Double
    ApplyDiscount = amount * 0.8
End Function
VB

解説:

  • ByVal で渡しているので、呼び出し先で amount を計算しても元の price はそのまま。
  • 戻り値で結果を返すので「副作用なし」。安全で読みやすいコードになる。
  • 基本は ByVal+戻り値、必要なときだけ ByRef が初心者におすすめの設計。

まとめ

  • 練習1: ByVal と ByRef の違いを体感 → 値が変わるかどうか。
  • 練習2: 複数の値を返すときは ByRef が便利。
  • 練習3: 安全に設計するなら ByVal+戻り値で副作用をなくす。

👉 次のステップとして、「自分の作りたい処理」を考えてみると理解が深まります。例えば「税金計算」「文字列の整形」「セルの値の更新」などを ByVal と ByRef で書き比べてみると、どちらが適しているかが自然に分かってきます。

VBA
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました