VBAで自動化 VBA一覧 セル・値の取得と貼り付け 値渡し・参照

【VBA】ByVal と ByRef の違いと使い方

Excel VBA でプロシージャ(SubやFunction)を作成する際、引数を渡す方法としてByValByRefを指定することができます。この指定によって、引数がプロシージャ内でどのように扱われるかが変わり、コードの影響を考慮するため動作の違いを理解して正しく使うことが重要です。

ByValByRefの違いをわかりやすく解説し、それぞれの具体的な使用例と注意点を紹介します。

ByVal と ByRef の基本的な違い

指定方法概要影響
ByVal値段渡し(値渡し)呼び出し元の変数はプロシージャ内で変更されない
ByRef参照を渡す(参照渡す)呼び出し元の変数がプロシージャ内で変更される

ByVal(値渡し)

  • 引き数の「値」だけがプロシージャに渡されます。
  • プロシージャ内で引数の値を変更しても、呼び出し元の変数には影響を与えません。

【構文】

Sub プロシージャ名(ByVal 引数名 As データ型)

' 処理内容

End Sub


【使用例】

Sub TestByVal()

Dim num As Integer
num = 10
Call ChangeValueByVal(num)
MsgBox "ByVal後の値: " & num ' 結果: 10 (変更なし)

End Sub

Sub ChangeValueByVal(ByVal x As Integer)

x = x + 10 ' ローカル変数 x の値を変更

End Sub

解説:

  • ChangeValueByValプロシージャでxの値を変更していますが、これは呼び出し元の変数numには影響を与えません。

ByRef(参照渡し)

  • 引数の「参照先」がプロシージャに渡されます。
  • プロシージャ内で引数の値を変更すると、呼び出し元の変数も変更されます。

【構文】

Sub プロシージャ名(ByRef 引数名 As データ型)

' 処理内容

End Sub


【使用例】

Sub TestByRef()

Dim num As Integer
num = 10
Call ChangeValueByRef(num)
MsgBox "ByRef後の値: " & num ' 結果: 20 (変更あり)

End Sub

Sub ChangeValueByRef(ByRef x As Integer)

x = x + 10 ' 呼び出し元の変数も変更

End Sub

解説:

  • ChangeValueByRefプロシージャでxを変更すると、numの値も変更されます。

ByVal と ByRef の使い分け

利用ケース適切な指定理由
呼び出し元の値を変更しない場合ByVal値渡しを行うことで、プロシージャ内での変更が呼び出し元に影響を与えません。
呼び出し元の値を変更したい場合ByRef参照渡しを行うことで、プロシージャ内での変更を呼び出し元に反映できる。
パフォーマンスが重要な場合(大きなデータ)ByRef値をコピーするByValより、参照を与えるByRefほうがメモリ効率が良い。

複数の値を計算して返す(ByRef)

2つの引数ByRefを渡し、計算結果を呼び出し元の変数に反映します。

Sub CalculateByRef()

Dim a As Integer, b As Integer

a = 5
b = 10
Call SwapValues(a, b)
MsgBox "入れ替え後: a=" & a & ", b=" & b ' 結果: a=10, b=5

End Sub

Sub SwapValues(ByRef x As Integer, ByRef y As Integer)

Dim temp As Integer
temp = x
x = y
y = temp

End Sub

解説:

  • SwapValuesxyを置き換えると、呼び出し元のabに反映されます。

呼び出し元の変数を保護(ByVal)

ByValを使用して、呼び出し元の変数が変更されません。

Sub ProtectOriginalValue()

Dim originalValue As Integer
originalValue = 20
Call DoubleValueByVal(originalValue)
MsgBox "元の値: " & originalValue ' 結果: 20 (変更なし)

End Sub

Sub DoubleValueByVal(ByVal x As Integer)

x = x * 2 ' 呼び出し元には影響なし

End Sub

解説:

  • DoubleValueByVal内部でx変更しても、originalValueは変更されません。

大きなデータの処理(ByRef)

配列をByRefに渡すことで、大量のデータを効率的に操作します。

Sub ProcessLargeData()

Dim dataArray(1 To 5) As Integer
Dim i As Integer

' 配列に値を設定
For i = 1 To 5

dataArray(i) = i

Next i

' 配列を変更
Call ModifyArray(dataArray)

' 結果を表示
For i = 1 To 5

Debug.Print "dataArray(" & i & ") = " & dataArray(i)

Next i

End Sub

Sub ModifyArray(ByRef arr() As Integer)

Dim i As Integer

For i = LBound(arr) To UBound(arr)

arr(i) = arr(i) * 2 ' 値を2倍にする

Next i

End Sub

解説:

  • 配列dataArrayByRef使って配置することで、配列全体を効率的に操作できます。

ByRef のデフォルト動作について

VBA では、引数をわかりやすく指定しない場合、独自にByRefが適用されます。

Sub DefaultByRef()

Dim num As Integer
num = 5
Call Increment(num)
MsgBox num ' 結果: 6 (変更あり)

End Sub

Sub Increment(x As Integer) ' 既定で ByRef

x = x + 1

End Sub

 

注意:引数をByValで作る場合は明確に指定する必要があります。

注意点とベストプラクティス

  1. 動作を把握する
    ByValまたはByRefを指定することで、意図しない挙動を阻止します。

  2. データ型に注意
    引き数のデータ型が一致していない場合、エラーや予期せぬ動作が発生する可能性があります。

  3. 値の変更を明確にする
    変数を変更する意図がある場合はByRef使用し、その意図をコードのコメントとすることが推奨されます。

まとめ

  • ByVal: 引数の値をコピーして転送するため、プロシージャ内の変更が呼び出し元に影響を与えません。
  • ByRef: 引数の参照を渡すため、プロシージャ内の変更が呼び出し元に反映されます。
  • 用途: 呼び出し元の値を保護する場合はByVal、変更を反映させたい場合や大きなデータを扱う場合はByRef使用する。

-VBAで自動化, VBA一覧, セル・値の取得と貼り付け, 値渡し・参照