VBA で Set が必要なときの見極め方
VBA を触って最初につまづくポイントの一つは、変数への代入のときに Set
を書くのか書かないのか、という問題だと思う。事実、自分もよく分かってなかった。
ということで、色んな文献を元に考え方を自分なりに整理して、Set
の要否を見分ける方法をまとめた。
Set
はオブジェクトの格納 → オブジェクトって?
Set
ステートメントは、オブジェクトをオブジェクト変数に格納する時に使う。
これだけで理解できる人は十分だが、イマイチよく分からない人は、「オブジェクトってなんぞや」をおさらいしてみる。
VBA におけるオブジェクト型とは、Object 型に属するもの。Workbook とか、Range とかもオブジェクト型のひとつ。Object はそれらオブジェクト型をひっくるめた総称オブジェクトである。
一方、Integer や Long などはオブジェクト型ではない。String や Date も、オブジェクト型には属さないので、Set
は書かなくて良い。
VBA が言語仕様として持っている標準的なデータ型のうち、Object 以外はオブジェクト型ではない、といえるだろうか。Workbook やら Range やらは、VBA の言語仕様に対して Excel が用意している オブジェクト型の API だ、と切り分けられれば分かりやすいかも。
オブジェクト型かどうかの見分け方
そうはいっても、どれがオブジェクト型にあたるのか、よく分からないかもしれない。たとえば以下のようなコード。
Dim r
Set r = Range("A1:A1")
Dim val
val = Range("A1:A1").Value
意図的に Dim
ステートメントに As
を書いていないが、Range はオブジェクト型の一種だ、と話したので、2行目の Set
は納得いくだろう。
しかし4行目は、同じ Range を触っているのに、Set が書かれていない。でもこれらは実行できるコードだ。
これは「オブジェクトがプロパティやメソッドを持っていること」を理解できていると迷わない。2行目は Range プロパティが返した Range オブジェクトが返されているため Set
が必要だが、4行目は Range オブジェクトが持つ Value
プロパティの値、つまり String 型の文字列が返されているため、Set
が要らない。
これをもっと平たく、プログラム初心者向けに表現するとしたら、「その先にドット .
を付けて何らかのプロパティが書ける状態であればオブジェクトなので Set
が要る、もうその先にドットの付けようがない状態であれば、オブジェクト型ではないことが多いので Set
は大抵不要」と言っても大概は通用するかもしれない。このドット .
とは、そのプロパティが持つメンバを書くためのもので、VBEditor なら「自動メンバ表示」機能で入力支援してくれる、アレだ。
さっきの例でいえば、Range("A1:A1").Value
の先には何のメンバもないため、Set
が要らない、と考えられる。
ちなみに先ほどのコードに型宣言を加えるとしたら、こうだ。
Dim r As Range ' Object もしくは Variant でも OK
Set r = Range("A1:A1")
Dim val As String ' Variant でも OK
val = Range("A1:A1").Value
Variant って何だ?
Variant は、様々なオブジェクトの総称型である Object 型を含む、全てのデータ型の総称。そのため、String でも Range でも何でも入る。
最悪、迷ったら Variant に入れて、Set
を書いたところで一度デバッグしてエラーになるかどうか、で Set
の要否を考えてもいいかも。そうしているうちに、ここでぼくが言いたかったことが何となくわかってもらえるかもしれない。