ツイッター出題回答
Variant仮引数のByRefとByValの挙動違い

ExcelマクロVBAとエクセル関数についての私的雑感
公開日:2020-07-05 最終更新日:2020-07-05

Variant仮引数のByRefとByValの挙動違い


ツイッターで出したVBAのお題です。
Variant型は、どんなデータ型も入れることができてしまいます。
具体的なデータ型の代わりに使用することで、より柔軟にVBA記述ができるようになります。
ただしこの便利さゆえに、逆に注意しなければならない挙動もあります。


お題のツイート

https://twitter.com/yamaoka_ss/status/1279642196430356487

【VBA問題】
Sub sample()
 Dim rng1 As Range, rng2 As Range
 Set rng1 = Range("A1:B1")
 Set rng2 = Range("A2:B2")
 Call sample_sub(rng1, rng2)
End Sub
Sub sample_sub(ByRef v1, ByVal v2)
 v1 = 1
 v2 = 1
 MsgBox WorksheetFunction.Sum(v1, v2)
End Sub
sampleの実行結果は?
・1
・2
・3
・4

VBA マクロ Variant ByRef ByVal 挙動違い

解説のツイート

以下で一連の解説ツイートをしています。

https://twitter.com/yamaoka_ss/status/1279781207975182337


Variantの仮引数に対して実引数でRangeオブジェクトを指定した場合、
ByRef、ByVal、呼ばれた関数ではどちらもRangeオブジェクトとして受け取ります。
しかし、このときByRefとByValでは一部挙動に違いが現れます。
受け取ったRangeオブジェクトに対するVBA記述によって違いが出てきます。


仮引数のVariantでRangeオブジェクトを受け取った場合のByRefとByValでの挙動の違いは、
Set代入した場合には、
ByRefなら参照私として呼び出し元も変化しますが、
ByValなら受け取るだけであり呼び出し元は変化しません。


通常RangeオブジェクトのValueに値を入れる場合は、
Range = 値
このLet代入でRangeが複数セルでも全てのセルのValueに値が入ります。
仮引数がRange型(As Range)であれば、Let代入は同じ動作となります。
しかしVariantでRangeを受け取った場合は、Let代入で挙動に違いが出てきます。


仮引数のVariant変数に対するLet代入では、
ByRefであれば、RangeのValueに値が入りますが、
ByValの場合は、Variant変数のRangeは破棄され、値そのものが変数に入ってしまいます。
これは、プロシージャー内でVariant変数を定義している場合を考えれば当然の結果として理解できます。


Dim v
Set v = Rangeオブジェクト
v.Value = 1 '①
v = 1 '②
①では、Rangeオブジェクトの全てのValueに値(1)が入ります。
②では、変数vに値(1)そのものが入ります。
ByValで受け取った場合は、プロシージャー内で変数定義したことと同じになります。


今回の問題では、
Call sample_sub(rng1, rng2)
Sub sample_sub(ByRef v1, ByVal v2)
v1 = 1 '①
v2 = 1 '②
①では、Rangeオブジェクトの全てのValueに値(1)が入ります。
②では、変数vに値(1)そのものが入ります。


v1は、Range("A1:B1")であり、全てのValueに1が入ります。
v2は、1がVariant/Integerとして代入されます。
結果として、
Sum(Range("A1:B1"), 1)
となるので、答えは3となります。

Variant変数の一般的な説明は、
「VBAのVariant型について」
https://excel-ubara.com/excelvba4/EXCEL_VBA_441.html
Variantデータ型は、他の何らかのデータ型として明示的に宣言されていない変数で、全てのデータ型を入れることができます。Variantデータ型には型宣言文字はありません。Variant型は、特別な値Empty、Error、Nothing、Nullを格納することもできます。




同じテーマ「ツイッター出題回答 」の記事

VBAのString型の最大文字数について
Variantの数値型と文字列型の比較
Variant仮引数にRange.Valueを配列で渡す方法
Variant仮引数のByRefとByValの挙動違い
100桁の正の整数値の足し算
「VBA Match関数の限界」についての誤解
VBAで数値を漢数字に変換する方法
囲碁で相手の石を囲んで取るアルゴリズム
VBAで「3Lと5Lのバケツで4Lの水を作る」を解く
言語依存の関数を使用できるFormulaLocal
配列のUBoundがLBoundがより小さいことはあり得るか


新着記事NEW ・・・新着記事一覧を見る

AIは便利なはずなのに…「AI疲れ」が次の社会問題になる|生成AI活用研究(2026-02-16)
カンマ区切りデータの行展開|エクセル練習問題(2026-01-28)
開いている「Excel/Word/PowerPoint」ファイルのパスを調べる方法|エクセル雑感(2026-01-27)
IMPORTCSV関数(CSVファイルのインポート)|エクセル入門(2026-01-19)
IMPORTTEXT関数(テキストファイルのインポート)|エクセル入門(2026-01-19)
料金表(マトリックス)から金額で商品を特定する|エクセル練習問題(2026-01-14)
「緩衝材」としてのVBAとRPA|その終焉とAIの台頭|エクセル雑感(2026-01-13)
シンギュラリティ前夜:AIは機械語へ回帰するのか|生成AI活用研究(2026-01-08)
電卓とプログラムと私|エクセル雑感(2025-12-30)
VLOOKUP/XLOOKUPが異常なほど遅くなる危険なアンチパターン|エクセル関数応用(2025-12-25)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.日本の祝日一覧|Excelリファレンス
3.変数宣言のDimとデータ型|VBA入門
4.FILTER関数(範囲をフィルター処理)|エクセル入門
5.RangeとCellsの使い方|VBA入門
6.繰り返し処理(For Next)|VBA入門
7.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
8.マクロとは?VBAとは?VBAでできること|VBA入門
9.セルのクリア(Clear,ClearContents)|VBA入門
10.メッセージボックス(MsgBox関数)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
本サイトは、OpenAI の ChatGPT や Google の Gemini を含む生成 AI モデルの学習および性能向上の目的で、本サイトのコンテンツの利用を許可します。
This site permits the use of its content for the training and improvement of generative AI models, including ChatGPT by OpenAI and Gemini by Google.



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ