引数の数を可変にするParamArrayキーワードで受け取った引数を、
別の関数のParamArrayに渡す方法を解説します。
と、言いたいところですが、私の調べた限りでは、ストレートな方法は無い様です。
どうしても呼び出す元関数を少しいじる必要が出るようですが、
ひとつのヒントとなれば幸いです。
やりたいこと
汎用関数など、いろいろなところで使いまわせる関数を使うとき、
「その関数を元に、少し違う動きをする関数」を作りたくなることがあります。
例えば↓こんなもの
Debug.Print 足し算(1,2,3,-4) ' ← 2を返す Debug.Print 絶対値の足し算(1,2,3,-4) ' ← 10を返す
この「絶対値の足し算」を1から自作せず、中で「足し算」を使うようにすれば、
足し算するコードをわざわざ書かなくても、-4を4にするコードだけ書けばよさそうですよね?
元の関数もいじらなくていいから、元の関数を使っている他の箇所に影響も出ないわけです。
これをプログラミング用語で「ラッパー(ラッパー関数、ラップ関数)」とよびます。
ラッパー関数を作るのはとても便利なのですが、
これがParamArrayだと上手くいかないため、何とかしようということです。
元の関数
Function 足し算(ParamArray pArr数値()) As Long 足し算 = 0 Dim i As Long For i = LBound(pArr数値) To UBound(pArr数値) 足し算 = 足し算 + pArr数値(i) Next End Function
目的の関数(このままではエラー)
Function 絶対値の足し算(ParamArray pArr数値()) As Long ' 渡された配列の中身を正の値にする Dim i As Long For i = LBound(pArr数値) To UBound(pArr数値) pArr数値(i) = Abs(pArr数値(i)) Next ' 元の関数を呼ぶ 絶対値の足し算 = 足し算(pArr数値) End Function
こんな感じで、ラッパー関数では、
「パラメータだけいじってあとは元の関数におまかせ!」
をやります。
※「絶対値にするついでに足しちゃえばいいのに」と言わないように。あくまでサンプルです。
この手法はとても便利なのですが、
ParamArrayをバトンすると、これではエラーが出るんですね。
何故エラーになるかというと、ラッパー関数に渡した時点では、
ParamArrayは「1」,「2」,「3」,「-4」という4つ数値からなる配列です。
しかし、これをそのまま元の関数に渡したときは、
「1,2,3,-4」という1つの配列からなる配列になってしまうからです。
「配列をParamArrayに渡した」という仕様そのままに、
配列の配列になってしまう訳ですね。
解決策(ただし、元関数をいじることになる)
これを何とかするには、「元の関数を」こう書き替えます。
Function 足し算(ParamArray pArr数値()) As Long ' 受け取ったParamArrayを直接処理せず、実際に処理に使う配列を作る Dim Arr数値 As Variant ' ParamArrayの第1要素が配列なら、その第1要素を処理配列に入れる If IsArray(pArr数値(LBound(pArr数値))) Then Arr数値 = pArr数値(LBound(pArr数値)) ' そうでないなら、ParamArrayをそのまま処理配列に入れる Else Arr数値 = pArr数値 End If 足し算 = 0 Dim i As Long For i = LBound(Arr数値) To UBound(Arr数値) 足し算 = 足し算 + Arr数値(i) Next End Function
ParamArrayを直接処理せずに、処理用の配列をワンクッション置き、
第1要素が | 処理配列に格納するのは |
---|---|
配列である | ParamArrayの第1要素 |
配列でない | ParamArrayをそのまま |
と場合分けして処理する配列を決めることで、
配列が直接渡された場合に備えています。
やってることは簡単ですし、コメント無くしてOption Base 1 も禁止しているなら、
Dim Arr数値: Arr数値 = IIf(IsArray(pArr数値(0)), pArr数値(0), pArr数値)
と、1行で済むので、対策としては悪くない気はします。
ただ、ラッパーの役割を果たせず、元関数を書き換えてしまっているのは、気持ちよくはないですね。
だいたいは同じ動きをしてくれますが、
完全に同じ挙動というわけにはいかないため注意が必要です。
一番わかりやすい注意点は、「元のParamArrayが、元々配列をうけとる想定の関数」では、当たり前ですがうまくいきません。
また、このコードのままでは、「元のParamArrayに要素を追加して渡す」ことはできません。第1要素が配列だった時点で、第2要素は無視していますからね。
一発解答な方法ではありませんので、関数ごとに微調整は必要になると思います。
ご注意ください。
なお、元の関数に「配列も受け取ることができる」という副産物ができるので、
Debug.Print 足し算(Array(1, 2, 3, 4)) Debug.Print 足し算(Split("1,2,3,4", ","))
このように、配列を渡して動かすことができるようになっています。
これはこれで便利な場面がありますね。
ということで、完全回答でなく申し訳ありませんが、
何かのヒントになれば幸いです。