※今回の記事はAriawaseというモジュールを使う前提のコードですので、一般的な環境で実行してもコードは動きません。
Ariawaseについてはこちらをご参照ください。
github.com
とあるブログ(既に閉鎖)で、ParamArrayを使った関数で再帰したいという変なお題が出されたので回答。
ParamArrayで再帰なんて、何に使うんだろうか。
いちおう、出来た。
多分以下で答えになっているはず。
Option Explicit Sub Sample20150630() Dim arr: arr = level(0, "a", "b", "c") End Sub Private Function level(ByRef i As Variant, ParamArray arg() As Variant) As Variant Debug.Print "Level " & i IncrPst i Dim v For Each v In arg Debug.Print Dump(v) & vbNewLine Next v If i = 10 Then End Else 'もしParamArrayの1つ目が配列なら、その配列の要素1を引数に渡す。 If IsArray(arg(0)) Then level i, arg(0) Else 'そうでなければ、そのまま渡す。 level i, arg End If End If End Function
再帰で躓いたときは、主な処理を一旦消してしまって再帰構造に集中した方が分かりやすい。
さらに再帰も外してシンプルに考えると、ただの関数呼び出しに展開できる。
Sub Sample20150630() Dim arr: arr = level_A("a") End Sub Private Function level_A(ParamArray arg() As Variant) As Variant level_B arg End Function Private Function level_B(ParamArray arg_b() As Variant) As Variant level_C arg_b End Function Private Function level_C(ParamArray arg_c() As Variant) As Variant Debug.Print Dump(arg_c) End Function
ParamArrayは複数の引数を配列として受け取るので、たとえば配列Aを渡せば配列Aを第一要素とする配列ができあがる訳である。
こうして配列がネストされていくことになるので、それを回避したい場合、第一引数が配列だった場合はその第一要素だけ渡してやれば良い。
最初に挙げた例ではvのDump結果はArray("a","b","c")と配列化されてしまっているが、配列化を避けたければ以下のようにすればできる。
Private Function level(ByRef i As Variant, ParamArray arg() As Variant) As Variant Debug.Print "Level " & i IncrPst i Dim v Dim arg2: arg2 = arg If IsArray(arg(0)) Then arg2 = arg(0) For Each v In arg2 Debug.Print Dump(v) & vbNewLine Next v If i = 10 Then End Else level i, arg2 End If End Function
7/1 追記
mmYYmmddさんから以下のコメントをいただいたので追記。
確認してませんけど、配列を複数渡した場合でも大丈夫でしょうか?
以下、複数配列に対応したもの
Sub Sample20150701() Dim arr: arr = level(0, Array("a", "b", "c"), Array("d", "e"), "f", "g") End Sub Private Function level(ByRef i As Variant, ParamArray arg() As Variant) As Variant Debug.Print "Level " & i i = i + 1 Dim arg2: arg2 = arg If UBound(arg) < 1 Then arg2 = arg(0) Dim v For Each v In arg2 Debug.Print Dump(v) & vbNewLine Next v If i = 10 Then End Else level i, arg2 End If End Function
まぁ、Level関数が何も返してないので、メインルーチンのarrに意味のあるデータは入らない。
なぜFunctionで再帰させたのかは分からないが、ネストは避けられているのでこれで元記事の要望とは合ってるんじゃないかと思われる。