ByVal と ByRef Macユーザー向け Excel VBA 入門 [08] Excel2019 for Mac

[08] ByVal と ByRef 、プロシージャ記述のオプション指定により結果が異なる場合(2つの例)
ByVal と ByRef 、文字列操作 と 数値操作 サンプル
・文字列操作 のサンプル
・数値操作 のサンプル
・デフォルト ByRef のため、状況に応じて ByVal (値渡し) キーワードを付加!
(注) 引数(パラメーター)指定した変数に「呼び出し先プロシージャの結果」を反映させたい場合のみ、 ByRef (参照渡し・ポインタ渡し) 指定を用います。
Macユーザー向け Excel VBA 入門 [08] ByVal と ByRef
まず、Excel メニューバーの [ヘルプ] - [更新プログラムのチェック] にて、適用されていないアップデートがあれば行ってください。
以下4つの操作方法がよく解らない方は、 Excel VBA 入門 [06] を参照して下さい。
(1) 「空のブック」Excelファイルを新規作成にて作成後、「名前を付けて保存…」にて、「Excel マクロ有効ブック(.xlsm)」ファイル形式を選び 任意の名前で保存。
(2) ( [マクロの記録] ボタンをクリックして)マクロの保存先に「作業中のブック」を指定後 [OK] ボタンをクリックし、「マクロの記録」を開始。 マクロ名は "Sample1" にて!
(3) 例えば「A3」セルを選択後、( [記録終了] ボタンをクリックして)「マクロの記録」を終了。
(4) [マクロ] ボタンをクリックして 先ほど作成した "Sample1" マクロを選択後 [編集] ボタンをクリックし、 VBEウィンドウ を開く。
![vba2019_primer[08] 04_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBCgT7nMMoby6cg1aM03Z0MvRx-8I2DJEUOwmPRjyPH3oQZDqqalkLjW1fxLyBEY1NUcyn886qPYMlkKIMVMGsMjaNTqeCw2tyLLeJG6AZdxFt0hqqs2BIcH4wj3ni1h9WV_LXkq6jT7Y/s0/20210813_04.png)
ByVal と ByRef 、プロシージャ記述のオプション指定により結果が異なる場合
' =========================================
Sub Sample1()
Dim buf As String ' 文字列型の変数を宣言
buf = "ABCDE" ' 変数に、文字列”ABCDE”を格納
Call Proc1(buf) ' プロシージャProc1の引数に変数を渡して呼出
MsgBox "Sample1: " & buf ' 変数の値を表示
End Sub
Sub Proc1(str As String) ' 省略すると、ByRef(参照渡し・ポインタ渡し)
str = str & "XYZ" ' 受け取った文字列に”XYZ”を加える
MsgBox "Proc1: " & str ' 変数の値を表示
End Sub
' =========================================
Sub Sample2()
Dim buf As String ' 文字列型の変数を宣言
buf = "ABCDE" ' 変数に、文字列”ABCDE”を格納
Call Proc2(buf) ' プロシージャProc2の引数に変数を渡して呼出
MsgBox "Sample2: " & buf ' 変数の値を表示
End Sub
Sub Proc2(ByVal str As String) ' 値渡し(変数のコピーが渡される)
str = str & "XYZ" ' 受け取った文字列に”XYZ”を加える
MsgBox "Proc2: " & str ' 変数の値を表示
End Sub
[VBE ウィンドウ]-[コード ウィンドウ]内の Sub Sample1() 以下を「上記のVBEコード」で置換します。
![vba2019_primer[08] 05_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7FB8CTQgKklzThOer5GOA2J6sWtK_RGy5ScRkCvSLj5Rhy1VlOATDxmjzvXPKuYKl0INKVFVPuZ1zthMEoDDpQjmTCIUFqGeYwpIEyb-ZR27uI57qmt26AHyEqAkEW5Fp85I1SZgH7Ms/s0/20210813_05.png)
コピペ あるいは 入力 ミスチェックのため、以下画面のように VBAProject のコンパイル を行い 「VBAコードの文法チェック」が可能です。
![vba2019_primer[08] 06_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilSwktFBpIcq7CjtrZOUiKIoO42gKIycMbFBbsiazb1xKonrbriwHkJvdlpLccuu_OI-zBD-9NtzK9ZxXtKwM0Jpq-EP4fGE2bpRDkUog3fCBuCO4iQzgCtn5sU3iZ9iyf8EHawrVFF2E/s0/20210813_06.png)
ByVal と ByRef 、文字列操作 のサンプル
「イミディエイト ウィンドウ」にて call sample1() [return] と入力し Sample1() プロシージャを実行すると、以下2つのメッセージボックス画面を表示。
![vba2019_primer[08] 08_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNG-kcgrgSbONnvz0PKqa176rAFzzHy2qs3rnwdEe-Kr-yUD3QPxoxGVBonL6NvW1cgpq6V-DzRIi43nhGspdJoYSFy77vgzIAHDoMFEkyPWsYR3M7Tgz-qg3T2YvmqU5om_dMvE28oY8/s0/20210813_08.png)
![vba2019_primer[08] 09_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4UrGueaGSg7q9aoYiQcHVDZy9j0itTCJqLuOS07rXRwnWV9wN8LCdQNjzd2SiywKRbYvi3Gzp65yZ2IyMuvEiIcxqfnmWSCCO7M1JkMSDejvkk816JWf9TBGWU-_Js2A4ietMGVOhdqY/s0/20210813_09.png)
キーワードを省略した場合も ByRef (参照渡し)となり、Proc1() の引数(パラメーター)に指定した変数の変更を確認!
「イミディエイト ウィンドウ」にて call sample2() [return] と入力し Sample2() プロシージャを実行すると、以下2つのメッセージボックス画面を表示。
![vba2019_primer[08] 10_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrgcrPAkaq4GP_JxBN5cUICDH4dhhPCqMj1ridDhD0n1IaWiiFTHiUotLOHohiz0K2H_sjZkOOEA3AxhOaPIZVuH2M1IKnXFGMrxqOkrnjUDA6ErEjQtgnR6YcgICaLG86o92ObaGuJM0/s0/20210813_10.png)
![vba2019_primer[08] 11_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA9FmLVTBvY0kSs1k9RcKbVrDNqUP9b-z2DcaiaYU2ZfTOTw5UMKhRMNI7SRfNk2dhHlRhyUTQVfVoxHtjgFf0Ht9IpEE7OK83ER8V6rcSzMZjG1ZyzifzQnZ_1LPJfI-UKrpB6ncXgKQ/s0/20210813_11.png)
ByVal キーワードを付加した場合、Proc2() の引数(パラメーター)には 指定した変数のコピー が与えられるため、 Sample2() 内の変数は変更されず元のまま 。
ByVal と ByRef 、数値操作 のサンプル
' =========================================
Sub Sample3()
Dim num As Integer ' 整数型の変数を宣言
num = 0 ' 変数に、 0 をセット
Call Proc3(num) ' プロシージャProc3の引数に変数を渡して呼出
MsgBox "Sample3: " & num ' 変数の値を表示
End Sub
Sub Proc3(num As Integer) ' 省略すると、ByRef(参照渡し・ポインタ渡し)
num = num + 1 ' 変数をインクリメント(+1する)
MsgBox "Proc3: " & num ' 変数の値を表示
End Sub
' =========================================
Sub Sample4()
Dim num As Integer ' 整数型の変数を宣言
num = 0 ' 変数に、 0 をセット
Call Proc4(num) ' プロシージャProc4の引数に変数を渡して呼出
MsgBox "Sample4: " & num ' 変数の値を表示
End Sub
Sub Proc4(ByVal num As Integer) ' 値渡し(変数のコピーが渡される)
num = num + 1 ' 変数をインクリメント(+1する)
MsgBox "Proc4: " & num ' 変数の値を表示
End Sub
[VBE ウィンドウ]-[コード ウィンドウ]内にて、 Sub Proc2 〜 End Sub 直後に「上記のVBEコード」を付け加えます。
コピペ あるいは 入力 ミスチェックのため、先程のように VBAProject のコンパイル を行い 「VBAコードの文法チェック」が可能です。
「イミディエイト ウィンドウ」にて call sample3() [return] と入力し Sample3() プロシージャを実行すると、以下2つのメッセージボックス画面を表示。
![vba2019_primer[08] 12_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAUBDEy6cgSzpVTO5uZ61_8nX2fDsi0AF7LInqUCzznlz3FihDJOZA8WBZK1kdl6g8IZ5GLHPzBeln_a9sG9l78uxevVFJ9Xvcej0Mgqm4ZLiHGB4mD65ZUJJw1CF9imUrqO85OQgLoXk/s0/20210813_12.png)
![vba2019_primer[08] 13_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwG_-oPNWflsnDnkYu50dDLLbMCMR-c9n5x1hAaMQ6foNv0tQti7WZJRmFNRXhHrtUmt3SqVw5YSL42byZXWBNe2m1Px7cA0LpYCHDKxubLiWvtMDQno3atsQxD5M069uHWJsmXzAq1yU/s0/20210813_13.png)
キーワードを省略した場合も ByRef (参照渡し)となり、Proc3() の引数(パラメーター)に指定した変数の変更を確認!
「イミディエイト ウィンドウ」にて call sample4() [return] と入力し Sample4() プロシージャを実行すると、以下2つのメッセージボックス画面を表示。
![vba2019_primer[08] 14_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnZZDfJXEmntpQcnP_ey04SBZANdsxaQdm8qsKXVly1GeGyWt0yDBUwoU4hdaLn80DnddS5FJXkuwHd9Ot7z_ilgm0ArvrarDhXCllgV3tMTqFB1bUlbqM2BD2iMqvSUCC56X420VShsM/s0/20210813_14.png)
![vba2019_primer[08] 15_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYfZ9uLmaNPJw4hCG1yL5wVDCEp1qwKoWcZaCQLTc7fM38rLqht-hRkuIvSZiRV9wQ8eCzkT1SZjRQD-SlV1Y9-3027CZpSvJoQA25EvoLH0bEmaidyh7maWpF-x-UbaVovaE1AiWqwvU/s0/20210813_15.png)
ByVal キーワードを付加した場合、Proc4() の引数(パラメーター)には 指定した変数のコピー が与えられるため、 Sample4() 内の変数は変更されず元のまま 。
デフォルト ByRef のため、状況に応じて ByVal (値渡し) キーワードを付加!
キーワードを省略した場合 ByRef (参照渡し・ポインタ渡し) となるため、状況に応じて ByVal (値渡し) キーワードを付加する必要があります。
ほとんどのプログラム言語では「値渡し」がデフォルト(省略値)ですが、なぜか Visual Basic 6.0 と VBA は「参照渡し」がデフォルトになっています。
「値渡し」をデフォルトにする理由は関数やプロシージャを一種のブラックボックスと考え、呼び出し元の変数が 呼び出し先にて勝手に変更されないようにするためです。
(不具合の発生を減らす努力を続ける事で)将来的にバグ回避に繋がりますので...
事実、最新の Visual Basic である VB.NET ( Visual Basic .NET ) では、 C# 等の他言語との互換性のため「値渡し」がデフォルトに変更されました。
結論として VBA では できる限り ByVal キーワードを付加して 呼び出し元の変数が勝手に変更されないようにし、敢えて 呼び出し元の変数に 呼び出し先プロシージャの結果を反映させたい場合のみ ByRef (参照渡し・ポインタ渡し)を用いるべき です。
なお、Function プロシージャの結果として返される変数は一つだけですが、プロシージャの引数(パラメーター)は複数指定できるので、ByRef を用いて 複数の結果を返すことも可能です。
Function プロシージャの結果として返される変数に、 配列や ユーザー定義型(構造体) を指定するほうが一般的ですが…
配列や ユーザー定義型(構造体) の説明は、また後日させて頂きます。
[command] + [Q] にてまず VBE を終了し、Excel のウィンドウ内を選択して [command] + [Q] にて Excel も終了させます。 「作業中のブック」を保存するか確認のダイアログ画面が表示された場合は 「保存」しましょう。 「自動保存」済みの場合、保存するかどうかの確認ダイアログ画面は表示されません。
次回は、 作成した ユーザー定義関数 を他のブックから呼び出す方法 を説明します。
最後まで読んでいただき、ありがとうございます。 また、お越しくださいませ。
// アタル