再帰関数 Macユーザー向け Excel VBA 入門 [07] Excel2019 for Mac

[07] Excel 再帰関数の作成
C言語みたいに「再帰」を利用したユーザー定義関数を作成してみよう!
・「階乗」関数の自作(ユーザー定義関数2)
・再帰関数とは?
・【おまけ】VBA「無限ループ(無応答)」対処方法のまとめ
・ByRef (参照渡し)と ByVal (値渡し)
(注) 学習のために作成するだけで、既に Excel には「階乗」を実装した FACT関数 が用意済み。
Macユーザー向け Excel VBA 入門 [07] 再帰関数の作成
まず、Excel メニューバーの [ヘルプ] - [更新プログラムのチェック] にて、適用されていないアップデートがあれば行ってください。
C言語みたいに「再帰」を利用した、ユーザー定義関数を作成してみよう!
「階乗」関数の自作(ユーザー定義関数2)
![vba2019_primer[07] 01_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtNkUxJqrGqvaO9OynqCokzqhtBeirVEK9zUuxLBBl_AYcNGUBmzeQkDkXInT5t7iB5BVRZvroatst206tU4hMuc7Z6pCueVlkSwsvT7h0EOe1ErMoxTh8Qt-uAWcoIbUwg6gZz2NJ-iw/s0/20210722_01.png)
前回「ユーザー定義関数」を作成したExcelファイルを開きます。
VBAコードが含まれているため、「マクロを有効」にします!
![vba2019_primer[07] 02_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgn0t-qXs6MGoe_8YHfIAvkXIkLUxX7q2ajja5nrxr0MMvZIJ5xZ0nmoSlUu5NIHsMV9u9lzTAMAD62eDF5FsLBTEQ0UNVhrJBcUeEcuGbfE7U3jMOjAr0sOltiHJWhnaHDxCVn-Upc7k/s0/20210722_02.png)
Module1 モジュールのVBAコードを表示するため、[開発]タブの [マクロ]ボタンをクリック。
次に前回作成した「マクロ名」を選択し、[編集]ボタンをクリック。
![vba2019_primer[07] 03_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikfcJzkOV4mGKWaqRR8edAj9VOvka65dUt9Rjrq0YnmJf1ZPeYjIrfyPxhHTfaT1ScNS6Ft0c0Gttd6hY5m1YDLYb6hPrUIxcVFtd3wzqERcEtwGbsfOdWIE8FHk791nFSpgzHamguWb4/s0/20210722_03.png)
VBEウィンドウが開き、前回作成した「マクロ」に対応するVBAコードが「コード ウィンドウ」に表示されます!
「コード ウィンドウ」にプロシージャ1つ分のVBAコードしか表示されていない場合は、「コード ウィンドウ」左下の右側のボタンをクリックすると モジュールのコード全体 が表示されます。
上記画面のように 下記 VBAコード を間違いなく追加で入力するか、(下記コード上でクリックするとコピー用のボタンが右上に表示されるため)コピー後に VBAコード を貼り付け。
「イミディエイト ウィンドウ」上で 追加した FuncTest2() ユーザー定義関数 を実行し、 動作を確認 しましょう。
? FuncTest2(3)
入力後に [return] キー押下にて 6 が表示され、 3 * 2 * 1 = 6 で問題ないようです。
? FuncTest2(10)
入力後に [return] キー押下にて 3628800 が返され、 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 3,628,800 のため 問題ありません。
Public Function FuncTest2(ByVal n As Long) As Long
Rem
Rem FuncTest2 = n! = n * (n - 1) * (n - 2) * ... * 1
Rem 【Excel関数 FACT(n) 】を実装(VBAコードでもC言語みたいに再帰関数を記述可能)
If n > 1 Then
FuncTest2 = n * FuncTest2(n - 1)
Else
FuncTest2 = 1 '(n <= 1) に対応するコードを誤って記述すると、無限ループ
End If
End Function
再帰関数とは?
自分自身を参照可能な状態を「再帰」と言います! その仕組みを利用し、「自分自身の関数」を呼び出し可能な関数を「再帰関数」と呼びます。
「再帰関数」を上手く利用するとコードを簡潔に記述することが可能ですが、終了条件を誤ると「無限ループ」に陥いるためコードの実装には注意が必要です。 (「再帰」の仕組みが利用できないプログラム言語も存在するが VBAを含むVBでも利用可能)
7行目の FuncTest2 = n * FuncTest2(n - 1) にて再帰呼び出しを行っていますが、前々回学習した If文で「 n の値 」により制限を加えなければ「無限ループ」に陥り終了しません。
今回だと (n <= 1) の場合、関数の返り値として 1 を返して 再帰呼び出しを終了させています。
引数 n に 10 を指定して呼び出した場合、 10 * FuncTest2(10 - 1) つまり 10 * FuncTest2(9) が実行されます。 順に FuncTest2(2) まで再帰呼び出しが行われ、FuncTest2(1) で 1 が返され「ループ」を終了。
【おまけ】VBA「無限ループ(無応答)」対処方法のまとめ
念のため、 VBA「無限ループ」(無応答状態も含む)対処方法 を纏めました!
【Mac】キーボードによる VBAの強制終了方法
(1) [command] + [.](ピリオド)
(2) [command] + [control] + [esc]
(3) [esc](2回押し)
(4) [command] + [option] + [esc] にて、Excel を選択し「アプリケーションの強制終了」を実行
【Windows】キーボードによる VBAの強制終了方法
(1) [Ctrl] + [Pause](または [Break] )
(2) [Esc]
(3) 「タスクマネージャー」のプロセスにて Excel を選択し、「強制終了」を実行
![vba2019_primer[07] 04_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbm7ZAgGtt0gbCoINY4H8zpoICnYO5mLlfvjCZByK4Tw9I_25FHKOKJDwLmHf0zAQwXhFbuqu9pndZIq3y4B7mxh8LkAw9t54bzcs1IENBQntSoB0HPDOB9sdSQ4yKyUgjn8e90P8QJ0k/s0/20210722_04.png)
上記画面のように ワークシート上のセル「C1」に =fu など3文字位を入力すると 「ユーザー定義関数」も併せて候補表示されるため FuncTest2 をクリックすると関数名が補完され、 =FuncTest2( と表示されます。
![vba2019_primer[07] 05_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdd4X83hGf1GCTihSEDtekskxHiRQw1j1Vp6pshKXzQPEypfqFY0tLi7Cqgs80SzVV5fuf9lHrwd9KXRMt4PrhlajTmIQo33bWHwHLX8SY8x670xVCC-cVNhVMoZOYdlIutndhtZjaDMk/s0/20210722_05.png)
通常の Excel関数と同様に「A1」セルをクリックすると =FuncTest2(A1 まで補完される。
![vba2019_primer[07] 06_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0LUSbFr-vAoOLM6qdK-3d4qXo91ysM6-L_pONPbNPkbaP4KatMoahKwb_nMJy_Xv6Yl9DkmHI77g0p0P7lzJTtlh2aFYA2Y2ngQROyltxAgfS3ZW3dLSwxpG5podj0cCpIWtYAX98PmA/s0/20210722_06.png)
[return] キーを押して =FuncTest2(A1) にて確定すると、「C1」セルに「 FuncTest2(1) ユーザー定義関数 」の実行結果が表示されます。
![vba2019_primer[07] 07_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXzMw70st_5f0B7I7WLyMiBGhjQnldFT8E1Tc75qg7UAD1d6AimvSZcATNyCwPWG8aUX9U7hlFqhayoVwGopSYpJSSnLVOcyPwO25mbDK2SMuX2OKK95GwaZXUlH3xXAHqmACK7YAI6Qk/s0/20210722_07.png)
「C1」セル選択後 [command] + [C] でコピー。
![vba2019_primer[07] 08_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5PFDdIB8CVqYFc4Ze0dhNdtAaBvhnoyBKzwq-sObC7GGUGYo0dog-_bizJvcp5Y1oUJiBo8BMHCiiFrKMbjElCPX4H56YtYwTNCkVfOlUwV3rPDVWN4cHSQ-BIulC_uSvRinqDma3vTc/s0/20210722_08.png)
「C2:C10」セル選択後に [command] + [V] で貼り付けすると、「 引数 n に 2 から 10 を指定した場合の FuncTest2(n) 実行結果 」が各セルに順に表示されます。
![vba2019_primer[07] 09_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_zFHX6QnfZcOFei6ah3cuz_urBgtIsevJ11I1MCU7Ue8k1C1RXUWofOnkDSYlZ-BVb0QIohlMJzInm2y4kDzxehaqZtzE7Gf4ehZX_rL3cHRbzeqYtrl7ITdApYA56Y8AAb3r-eoBECc/s0/20210722_09.png)
「D1」セルに =fact( 入力後 「A1」セルをクリックし、[return] キーで確定。 ( =FACT(A1) と表示 )
![vba2019_primer[07] 10_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI7Fmpi0UeZQ6mRdO51qSuX7klCSemS7JWUUZebO40UqGZOZNKpAnNy3CiXFxvQG0WXHV8K1HpMQm-A1hlpGKqQIODdrF5_rDULy-Sz-83V1skfUEzQI6TX56r52-lsLOHQX6pDh4W6Vc/s0/20210722_10.png)
「D2:D10」セル選択後に [command] + [V] で貼り付けすると、「 引数 n に 2 から 10 を指定した場合の FACT(n) 実行結果 」が各セルに順に表示されます。
![vba2019_primer[07] 11_png](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUQx2AP6HVItOc5fN5hD1I7s2TZpAxSOYRmBB1YxoDLXCBlbXD_e5W22zM9-i-UANplKI5PkWX4t-ReQeCtOH1XQQci5ucIKKyktA3QmD5C1JWRk1WVmRgrbRWacBQ7zpu1NV0V0KXCV8/s0/20210722_11.png)
「FuncTest2() ユーザー定義関数」と Excelに元々用意されている「FACT関数」の実行結果が 同一となる事を確認します!
【復習】条件分岐の If 文(ステートメント)
If (条件A) Then
・・・ ' (条件A)に合致するときに 実行される命令(複数行も可)
End If
あるいは
If (条件A) Then
・・・ ' (条件A)に合致するときに 実行される命令(複数行も可)
Else
・・・ ' (条件A)に合致しないときに 実行される命令(複数行も可)
End If
(If文の)ネストと呼ばれるが、If文 の中に If文 を記述することも可能。
また、条件分岐には Select Case 〜 ステートメント もありますが、また後日説明いたします。
ByRef (参照渡し)と ByVal (値渡し)
1行目の関数の 引数(パラメーター) n に ByVal というキーワードが付いていることに気付いた方もみえるでしょう。
ByVal は By Value (値渡し)、ByRef は By Reference (参照渡し・ポインタ渡し) の意味で、VBA を含む VB6.0系では 省略すると ByRef 指定 となります。
実は FuncTest2() 関数は ByRef でも結果は変わりませんが、効率を重視して ByVal を選択しました。
ByVal 指定だと変数のコピーが利用されるため、 呼び出し元 の 変数の値は変更されません。
呼び出し元 の 変数の値が(無意識に)変更されるとバグになりやすいため、 デフォルト ByVal がプログラム言語の主流です。
事実、C# と同じになる様に、 VB.NET ( Visual Basic .NET ) では デフォルトが ByVal に変更されています。
次回は、この指定により結果が異なる場合の例を示します。
[command] + [Q] にてまず VBE を終了し、Excel のウィンドウ内を選択して [command] + [Q] にて Excel も終了させます。 「作業中のブック」を保存するか確認のダイアログ画面が表示された場合は 「保存」しましょう。 「自動保存」済みの場合、保存するかどうかの確認ダイアログ画面は表示されません。
次回は、 ByRef (参照渡し)と ByVal (値渡し)、この指定により実行結果が異なる場合がある事を学習します!
最後まで読んでいただき、ありがとうございます。 また、お越しくださいませ。
// アタル