値が無い場合の表現
VBAでは値が入っていないときの表現がいくつもあります。
- Empty
- Nothing
- Null
- “”
- vbNullString
これらの違いを説明します。
Empty
Emptyは、主に2つの場合で発生します。
1つは空白セルの値。もう1つはVariant型の変数の初期値になります。
VBAでは変数の定義時に型を指定せず暗黙の型変換とした場合はVariant型(なんでも型)になるためEmptyになります。セルや変数の値がEmptyかどうかを判定するにはIsEmpty関数を使いますが、””と比較してもちゃんと動作します。
以下のような感じで使います。
1 2 3 4 5 6 7 8 9 10 11 |
Sub CheckVoidCell() Dim s s = Range("A1").Value If (IsEmpty(s) = True) Then '// If (s = "") Then Debug.Print "入力なし" Else Debug.Print "入力あり" End If End Sub |
5行目ではA1セルに値をIsEmpty関数で判定していますが、6行目のようにIsEmpty関数を使わず、””と比較して書いてもちゃんと動作します。
ちゃんと動作する理由は、型指定をしなかったため暗黙でVariant型となった変数sが、=の右辺の””と比較する際に、””が文字列であることからEmptyをString型の””に変換した上で比較を行い、比較一致とみなしているためです。
1 2 3 |
If (s = "") Then ↓ If ("" = "") Then |
上のコードのようにセルの値が入ってるかどうかを調べる場合は、IsEmpty関数よりも””と比較する方が直観的に分かりやすいため、私は6行目のように s = “” と書くことが多いです。
Nothing
Nothingはちょっとややこしいです。
NothingはObject型の変数の初期値です。Object型はFileSystemObjectクラスなどのクラス型の変数のことを指します。
いろんなサイトでも「Object型はオブジェクトを入れる」という、特に初心者にはなんとも分かりにくい説明をしてあるのですが、実際にObject型変数に入るのはクラスのインスタンスになります。
インスタンスとはクラスの実体になります。クラスが変数や型などの形だけを定義したものを指し、インスタンスがそれらの変数に実際に値を入れる領域を確保したものを指します。
でも、こんなことは知らなくても書き方さえ知ってれば使えます。
そのクラスがたくさんあるため総称して「オブジェクト」という言い方をしていますが、それが余計にわかりにくくしている気がします。
Object型の変数はかならずSetステートメントを利用して他のObject型の変数への参照を行う必要があります。
参照の際は通常、CreateObject関数を使います。
Nothingも参照時と同様にSetステートメントと一緒に利用する必要があり、別のObject型変数への参照を解放するために使います。
参照とは関数の引数をByRefで渡す場合の考え方と同じです。
このような書き方をします。ちょっと長いですが内容は簡単です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
Sub SetObject() Dim objRef As Object '// 処理で使用する際に参照するオブジェクト Dim obj As Object '// 処理で使用するオブジェクト '// FileSystemObjectクラスのオブジェクトを作成 Set objRef = CreateObject("Scripting.FileSystemObject") '// 上で作成したオブジェクトを参照 Set obj = objRef '// FileSystemObjectクラスのCopyFileメソッドでファイルをコピー obj.CopyFile "C:/web/a.txt", "C:/web/test/" '// 参照を解放 Set obj = Nothing '// Nothingで解放後に上と同じ処理を行おうとしてもエラーになる。 '// obj.CopyFile "C:/web/b.txt", "C:/web/test/" '// 再度オブジェクトを参照 Set obj = objRef '// 再度参照後は正しく動作する obj.CopyFile "C:/web/b.txt", "C:/web/test/" '// 参照先を解放 Set objRef = Nothing '// 参照先を解放後にオブジェクトを使用(正しく動作する) obj.CopyFile "C:/web/c.txt", "C:/web/test/" If (obj Is Nothing) Then Debug.Print "Nothing" ElseIf (Not (obj Is Nothing)) Then Debug.Print "Not Nothing" End If End Sub |
9行目で参照したあとに、15行目でNothingを指定していますが、変数自体が使えなくなるわけではなく、どのObject変数も参照しなくなっただけの状態のため、21行目のように再度参照を行うと使えるようになります。
15行目でNothingを設定したあとに18行目のように使おうとしても「実行時エラー’91’ オブジェクト変数または With ブロック変数が設定されていません。」とエラーになります。なお、関数が終わる直前で Set obj = Nothing を入れていません。しかし無くても問題ありません。
Object型を使ったコードでは関数の最後に当たり前のように Set obj = Nothing の一文が入っているのですが、ほとんどの場合においてこれは意味がありません。
なぜかというと、Object型の変数が解放されるのはNothingが代入されたときではなく、関数の処理が終わってObject型変数の役目が終わったときに解放されるためです。
また、27行目で参照先を解放後に、30行目を実行しても正しく動作します。
参照先の変数が解放されたにも関わらず動作するのは、Setステートメントで参照している実体が6行目のCreateObjectで残っているためです。
Object型変数がNothingかどうかを判定するには、以下のように書きます。
1 |
If (obj Is Nothing) Then |
反対にNothingでないことを判定するには、以下のように書きます。
1 |
If (Not (obj Is Nothing)) Then |
Null
NullはVariant型に設定される値ですが、Variant型の初期値はEmptyですのでNullは意図的に代入しなければ設定されません。Emptyは値がまだ設定されていない「未設定」状態を表し、Nullは値が「無い」ことを表します。
「未設定」と「無い」は意味が異なります。
Nullが発生する場面はあまりなく、高さが異なる複数行を選択した場合のRowHeightプロパティや同様に異なる幅の複数列でのColumnWidthプロパティを使ったときのように、対象値が異なる複数セルを参照したときにNullが返却されるぐらいです。
書式が異なる複数セルを参照した場合のNumberFormatプロパティなどもそうですね。
それ以外では、外部のDBを使うような場合でない限りNullが設定されることは無いんじゃないかなあ、という気がします。
Nullは上に書いた通り、明示的に、obj = Null のような書き方をしない限り入りませんし、そういう書き方をする必要もないため、Nullを使う場面はほとんどないと思います。
Nullかどうかの判定には、IsNull関数を使います。
1 2 3 4 5 6 7 8 9 10 11 |
Sub NullTest() Dim a a = Null If (IsNull(a) = True) Then Debug.Print "Null" Else Debug.Print "Not Null" End If End Sub |
IsNull関数とIsEmpty関数がごちゃごちゃになりそうですが、IsEmpty関数だけ使う、と思っていて大丈夫と思います。
少なくとも私はIsNull関数を使った記憶がほとんどありません。
上にあげたRowHeightプロパティやColumnWidthプロパティでもNullは発生しますが、そういう複数セルの参照ではループでセルを1つずつ処理した方がいいのでIsNull関数を使う場面はやはりあまり記憶にないです。
“”(空文字列)
“”はよく使われる値で、見たままの値です。String型です。””かどうかの判定もそのまま使います。
文字列変数の初期化によく使われますね。
1 2 3 4 5 6 7 8 9 10 |
Sub VoidStrTest() Dim s s = "" If (s = "") Then Debug.Print "Void" Else Debug.Print "Not Void" End If End Sub |
vbNullString
vbNullStringはString型変数の初期値です。厳密には””とは違うのですが、””と同じと考えてもらっても問題ありません。実際、String型変数の初期値をウォッチ式で見ても、”” と表示されます。
vbNullStringは値を持っていないことを示しており、簡単に言えば代入されていない状態になります。代入されているかどうかを調べるにはStrPtr関数を使えば分かります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Sub vbNullStringTest() Dim s As String If (StrPtr(s) = 0) Then Debug.Print "代入していない" '// こちらが出力 Else Debug.Print "代入している" End If s = "" If (StrPtr(s) = 0) Then Debug.Print "代入していない" Else Debug.Print "代入している" '// こちらが出力 End If End Sub |
上のコードの出力結果は以下になります。
1 2 |
代入していない 代入している |
なんでこんなものがあるのかというと、入力ダイアログなどの挙動に関係があります。「代入されていない」状態など持たずに初期値を””にしてしまえばいいのに、と思ってしまいそうですが、画面操作上そういう場面が発生することがあります。
入力ダイアログでテキストボックスに値を入れなかった場合は””、キャンセルボタンを押した場合は””ではなく代入していない、という状態になります。こういう外部の動作によるString型の戻り値が代入されているのかどうかが変わるため、vbNullStringは用意されています。
言い方を変えれば、こういう外部操作が関係なければ、””と同じとして考えて問題ありません。
まとめ
上の内容を整理しました。
種類 | 型 | 判定方法 | 判定例 |
---|---|---|---|
Empty | Variant | IsEmpty関数 | If (IsEmpty(s) = True) Then |
Nothing | Object | Is Nothing | If (obj Is Nothing) Then |
Null | Variant | IsNull関数 | If (IsNull(a) = True) Then |
“” | String | 単純比較 | If (s = “”) Then |
vbNullString | String | StrPtr関数 | If (StrPtr(s) = 0) Then |