2018年07月14日

VBA覚書 Dimステートメントについて

以下のコードを実行したとき、cntは初回のDimを通った時は初期値を持つが、
2回目以降は前回の値を保持したまま。つまりDimを通っても初期化されない。
JavaでいうFor文の{}内スコープの感覚で「初期化されるだろう」と勘違いして躓いた。
Dim i As Integer
For i = 1 To 5
    Dim cnt As Integer
    cnt = cnt + 1
    Debug.Print cnt
Next
ちなみに、リファレンスでは「プロシージャで Dim ステートメントを使用するとき、通常、 Dim ステートメントをプロシージャの最初に配置します。」との但し書きがある。(プロトタイプ宣言の様な書き方は前世代的な感じもするが)
ただ、少なくともVBAに関してはFor内のDimの使用は混乱のもとなので今後はやめようと思う。

■Dim ステートメント
'固定長配列(メモリ確保する)。
Dim foo(10) As Integer

typeを省略するとVariantとなる。なお、For Each文を使う場合は必ずVariantにする必要あり。
指定する値は添え字の最大値(※要素数ではない!ここが他の言語と違う)。
10を指定した場合は0から10までの「11個の要素」を確保する。
添え字の下限値を指定したい場合は以下のようにする(1以上も可能)。
Dim foo(5 to 10) As Integer

'可変長配列(メモリ確保しない)。
Dim foo() As Integer
使用するにはこの後かならずReDimでメモリの確保をする必要あり。

■Dim ステートメントのNewの扱い
Setステートメントを省略するためのものではない。「最初の参照でオブジェクトの新しいインスタンスが作成される」のであって、宣言と同時にインスタンスが作成されるわけではない。

■ReDim ステートメント
Dimではメモリ確保の際に動的な値を指定できないため、ユーザ入力値など可変の配列を確保したい場合はReDimを使う。
ReDim foo(動的な値) As Integer
既存の値を保持したまま添え字の最大値を変更する場合はPreserve を付ける。
ReDim Preserve foo(動的な値)

■Erase ステートメント
固定長配列の場合
 各要素を初期化する。
可変長配列の場合
 メモリを解放する。次回使用するには必ずReDimする必要あり。
Erase arraylist

■Option Base ステートメント
配列の添字の既定の下限(0 or 1)を宣言する(モジュール単位)
Option Base 0

■UBound 関数/LBound 関数
最大/最小の添え字をLongで返す。
メモリが確保されてない可変長配列を指定するとエラーとなる。

Microsoft VBA 言語リファレンス
https://msdn.microsoft.com/ja-jp/vba/language-reference-vba/articles/dim-statement
https://msdn.microsoft.com/ja-jp/vba/language-reference-vba/articles/redim-statement
https://msdn.microsoft.com/ja-jp/vba/language-reference-vba/articles/erase-statement
https://msdn.microsoft.com/ja-jp/vba/language-reference-vba/articles/option-base-statement
タグ:VBA
posted by Hiro at 13:01| Comment(0) | プログラム