VBAで動的配列を使うときに自分で変数を宣言した場合は初期化のタイミングがわかるけど、共通に使う関数の場合は引数の配列が初期化済みかどうか判定したい場合がある。
逆に初期化されていないことを判定する場合はこうなる。
まず、VBAのBooleanは以下のように定義されている。
Visual Basic 言語リファレンス ブールデータ型
他の数値型が Boolean 値に変換される場合、0 は False に、その他の値はすべて True になります。Boolean 値が他のデータ型に変換される場合、False は 0 に、True は -1 になります。
Not演算子はビット反転演算子でもあるので、配列型の変数にNotを適用したときに数値型に変換されているみたい。
Visual Basic 言語リファレンス Not演算子
また、Not 演算子は、変数のビット値を次の表に示すように反転し、result の対応するビットを設定します。
ちなみにNotを付けないで、いきなり配列型の変数を条件判断に使おうとすると構文エラーになる。
さらに配列を格納したVariant型変数にNotを適用しようとすると実行時エラー13(型が一致しません)になる!
によると
Static semantics:
§ A logical operator is invalid if the declared type of any operand is an array or a UDT.
うーん、invalid としか書かれていない。。。
また、配列を格納したVariant型変数にNotを適用しようとすると実行時エラーが発生したのも言語仕様に書いてある。
Runtime semantics:
§ If the value type of any operand is an array, UDT or Error, runtime error 13 (Type mismatch) is raised.
これからすると、配列変数にNotを適用するのは言語仕様的に正しい作法というより、実装依存になるのかなー。
引数が配列でない場合もFalseを返す仕様にすると、以下のようになるのかな。
Not Not
こんなときに使われるイディオムとして Not Not で比較するというものがある。
Dim arr() As String
ReDim arr(0)
If Not Not arr Then
Debug.Print "arr is ReDim."
End If
逆に初期化されていないことを判定する場合はこうなる。
Dim arr() As String
If (Not arr) = -1 Then
Debug.Print "arr is not ReDim."
End If
なんで
なんで、こんな書き方ができるんだろう。まず、VBAのBooleanは以下のように定義されている。
Visual Basic 言語リファレンス ブールデータ型
他の数値型が Boolean 値に変換される場合、0 は False に、その他の値はすべて True になります。Boolean 値が他のデータ型に変換される場合、False は 0 に、True は -1 になります。
Not演算子はビット反転演算子でもあるので、配列型の変数にNotを適用したときに数値型に変換されているみたい。
Visual Basic 言語リファレンス Not演算子
また、Not 演算子は、変数のビット値を次の表に示すように反転し、result の対応するビットを設定します。
ちなみにNotを付けないで、いきなり配列型の変数を条件判断に使おうとすると構文エラーになる。
' 構文エラー!' If arr = 0 Then Debug.Print "arr is not ReDim." End If
さらに配列を格納したVariant型変数にNotを適用しようとすると実行時エラー13(型が一致しません)になる!
Dim arr() As String Debug.Print (Not arr) ' -1' Dim varArr() As Variant Debug.Print (Not varArr) ' -1' Dim var As Variant var = varArr Debug.Print (Not var) ' Error 13 occurred.'
VBAの言語仕様によると
[MS-VBAL]: VBA Language Specification 5.6.9.8 Logical Operatorsによると
Static semantics:
§ A logical operator is invalid if the declared type of any operand is an array or a UDT.
うーん、invalid としか書かれていない。。。
また、配列を格納したVariant型変数にNotを適用しようとすると実行時エラーが発生したのも言語仕様に書いてある。
Runtime semantics:
§ If the value type of any operand is an array, UDT or Error, runtime error 13 (Type mismatch) is raised.
これからすると、配列変数にNotを適用するのは言語仕様的に正しい作法というより、実装依存になるのかなー。
オーソドックスにOn Errorで対処する
Not Notイディオムがあまりよろしくないとすると、On Errorで対処するしかない。引数が配列でない場合もFalseを返す仕様にすると、以下のようになるのかな。
'arrがReDimで初期化済みであれば、Trueを返す' 'それ以外であれば、Falseを返す' Function IsRedim(ByRef arr As Variant) As Boolean On Error Resume Next Err.Clear IsRedim = CBool(UBound(arr)) IsRedim = (Err.Number = 0) End Function
0 件のコメント:
コメントを投稿