【入門編】Call By ReferenceとCall By Value:引数の渡し方でバグを防ぐ – Excel VBA解析バイブル

スポンサーリンク

こんにちは。業務自動化の世界へようこそ。

「マクロの記録」でコードを書き出し、少しずつ自由に動かせるようになったあなたへ。次に立ちはだかる壁は、「なぜか変数の値が勝手に変わっている」という怪奇現象ではないでしょうか。

そのバグ、実はVBAの引数の渡し方、`ByRef`と`ByVal`を理解することで根絶できます。これを知ることは、単なる文法知識を超えて「プログラムのデータ管理」という設計思想に触れるということです。

さあ、VBAの深淵を少しだけ覗いてみましょう。

1. そもそも「引数」を渡すとはどういうことか?

関数(SubやFunction)にデータを渡すとき、私たちは「値そのもの」を渡しているつもりになりがちです。しかし、VBAのデフォルト設定では「そのデータが入っている住所(メモリ上の場所)」を渡しています。

これが `ByRef`(バイ・レフ:参照渡し) です。

一方で、`ByVal`(バイ・バル:値渡し) は、そのデータの「コピー」を渡します。

図解的イメージ

  • ByRef(参照渡し): 共有フォルダにある書類を直接編集してもらう。相手が書き込めば、元の書類も変わる。
  • ByVal(値渡し): 書類のコピーを渡す。相手が何を書こうが、あなたの手元の原本は汚れない。

2. なぜ `ByRef` がバグの温床になるのか

VBAの恐ろしい仕様は、何も書かないとデフォルトで `ByRef` になる点です。つまり、あなたが意識せずに関数を呼び出すたびに、元の変数が「書き換えられるリスク」を抱えているのです。

以下のコードを見てください。

Sub Main()
Dim myScore As Long
myScore = 80

‘ 関数を呼び出す
CalculateBonus myScore

‘ ここで myScore はどうなっているか?
MsgBox “最終スコア: ” & myScore
End Sub

‘ ByRef(省略時)で受け取ると…
Sub CalculateBonus(ByRef score As Long)
‘ 内部で勝手に値を書き換えてしまう
score = score + 20
End Sub

この結果、`myScore` は `100` になります。もしあなたが「元々のスコアは80のまま、計算結果だけを知りたかった」のであれば、これは致命的なバグの始まりです。

3. 「意図しない書き換え」を防ぐための鉄則

バグを生まないエンジニアは、「デフォルトを信用しない」という原則を徹底しています。

鉄則:原則 `ByVal`、必要なら `ByRef`

基本的には、引数はすべて `ByVal` で渡す習慣をつけてください。関数の中で変数を書き換える必要があると確信した時だけ、明示的に `ByRef` と書くのです。

‘ 安全な設計:コピーを渡すので、元の値は絶対に守られる
Sub CalculateBonusSafe(ByVal score As Long)
Dim finalScore As Long
finalScore = score + 20
MsgBox “計算後の値は ” & finalScore & ” ですが、元データは汚しません。”
End Sub

4. 現場で役立つ「使い分け」の判断基準

初学者のうちは、以下のガイドラインに従うだけでコードの品質が劇的に変わります。

  • `ByVal` を選ぶべき場面(9割がこれ):
  • 計算結果だけを出したいとき
  • 文字列や数値を関数に渡して加工したいとき
  • 「元の値は変えたくない」という安心感が欲しいとき
  • `ByRef` を選ぶべき場面(1割の例外):
  • オブジェクト(RangeやWorksheetなど)を操作するとき
  • 一つの関数で複数の値を同時に変更・返却したいとき(上級者向けの手法)

まとめ:あなたのコードを「堅牢」にするために

プログラミングにおいて、「自分の予期しないタイミングでデータが変わる」ことほど怖いものはありません。

1. 省略しない: `Sub Test(ByVal val As Long)` のように、必ず明示的に書く。
2. 守りを固める: 基本は `ByVal`。変数のコピーを渡して、原本を保護する。
3. 意識を持つ: 渡しているのは「値」なのか「住所」なのか、常に想像する。

この感覚を掴めば、あなたはもう「マクロの記録」を卒業したエンジニアの入り口に立っています。VBAは、こうした小さな設計の積み重ねで、驚くほど安定した自動化ツールへと進化します。

ぜひ、今書いているコードの引数に `ByVal` を付けてみてください。それだけで、あなたのコードの「格」が一つ上がりますよ。応援しています。

タイトルとURLをコピーしました