前提
この記事における「要素数0の配列」は
『UBound()
やLBound()
に渡してもエラーが発生せず、UBound() - LBound() + 1
を評価すると0となる一次元配列』とします。
はじめに
VBAでは、変数宣言などの記述で要素数0の配列を作成できません。
'Option Base 0
Dim myArray() As Variant
ReDim myArray(0) ' 要素数0ではなく添え字が0~0の要素数1個の配列
しかし、一部の型の配列に関してはVBA標準機能・組み込み関数の組み合わせで作成できます。
この記事では、その作成方法を記載しています。
また、この記事の方法はWindows環境でしか動作を確認していません。
Windows 7 Microsoft Excel 2010 32bit
Windows 8.1 Microsoft Excel 2013 32bit
Windows 10 Microsoft Excel 2016 64bit
備考
以下のページのようにSAFEARRAY操作用のWindows APIを使用すれば、汎用的に要素数0の配列を作成できます。
使用されているWindows API
SafeArrayAllocDescriptor function | Microsoft Docs
使用例
'引数1 :作成したい配列の次元数(VBAなら基本1でいいはず)
'引数2 :任意の型の配列
'返り値:成功・失敗(0なら成功)
Private Declare PtrSafe Function SafeArrayAllocDescriptor Lib "oleaut32" ( _
ByVal cDims As Long, _
ByRef ppsaOut() As Any _
) As Long
Property Get EmptyLongArray() As Long()
Dim apiResult As Long
apiResult = SafeArrayAllocDescriptor(1, EmptyLongArray)
If apiResult <> 0 Then Err.Raise 5
End Property
要素数0の配列を取得する記述
VBAの標準機能では以下の型の要素数0の配列を作成できます。
- Variant
- String
- Byte
- オブジェクト
また記述の都合上、それぞれの配列を取得するプロシージャとして紹介します。
Variant型
比較的有名な方法だと思われますが、Array 関数に引数を渡さず実行すると得られます。
ヘルプにも記載されていますが、Option Base 1
が設定されているかつArray()
と記述するとVariant(1 To 0)
の配列となるため注意が必要です。
Property Get EmptyVariantArray() As Variant()
Let EmptyVariantArray = VBA.Array()
End Property
String型
Split 関数に長さ0の文字列を渡して実行すると得られます。
Property Get EmptyStringArray() As String()
Let EmptyStringArray = VBA.Split(VBA.vbNullString)
End Property
Byte型
VBAのString型は内部的にはByte型の配列として扱われており、相互に代入が可能です。
長さ0の文字列をByte型の配列に代入すると、要素数0の配列が得られます。
Property Get EmptyByteArray() As Byte()
Let EmptyByteArray = VBA.vbNullString
End Property
オブジェクト型
正直なぜこのような動作になるのかわかっていませんが、初期化していないObject型の動的配列を変数に代入すると、要素数0の配列になります。
また、返り値をObject()
とするとObject()
型の変数にしか代入できなくなるためVariant
としています。
Property Get EmptyObjectArray() As Variant '= Object()
Dim o() As Object '-> Object()
Let EmptyObjectArray = o
End Property '-> Object(0 To -1)
動作確認用コード
上記プロシージャのTypeNameとUBound
・LBound
の結果を出力します。
Sub SampleEmptyArray()
Dim v() As Variant
v = EmptyVariantArray
Debug.Assert (UBound(v) = -1) And (LBound(v) = 0)
Debug.Print TypeName(v)
Debug.Print "UBound="; UBound(v)
Debug.Print "LBound="; LBound(v)
Dim s() As String
s = EmptyStringArray
Debug.Assert (UBound(s) = -1) And (LBound(s) = 0)
Debug.Print TypeName(s)
Debug.Print "UBound="; UBound(s)
Debug.Print "LBound="; LBound(s)
Dim b() As Byte
b = EmptyByteArray
Debug.Assert (UBound(b) = -1) And (LBound(b) = 0)
Debug.Print TypeName(b)
Debug.Print "UBound="; UBound(b)
Debug.Print "LBound="; LBound(b)
Dim c() As VBA.Collection
c = EmptyObjectArray
Debug.Assert (UBound(c) = -1) And (LBound(c) = 0)
Debug.Print TypeName(c)
Debug.Print "UBound="; UBound(c)
Debug.Print "LBound="; LBound(c)
End Sub