🐡
VBA の SET キーワードは飾りなのか?
VBA の代入は対象の型に応じて書き方が変わります。
- 値を代入する場合 :
Let v = aのようにする (LETは省略可能) - オブジェクトを代入する場合 :
Set v = oのようにする (SETは必須)
この違いを素直に受け入れるのは簡単です。
でも、ちょっと待ってください。インタプリタは型情報を持っているのですから、代入式の右辺が値かオブジェクトかも判断できるはずです。なぜ人間がその判断をしないといけないのでしょうか?
実は Set の有無で挙動が変わることがあるのです。
例えば次のコードを見てみましょう。
Dim v As Variant
Dim rng As Range
Set rng = ThisWorkbook.Sheets(1).Range("A1")
rng.Value = "test"
Let v = rng ' Let は省略可能
Debug.Print TypeName(v) ' -> String と表示される
Set v = rng
Debug.Print TypeName(v) ' -> Range と表示される
どうして挙動が変わったのでしょうか?
Range のドキュメントを見ると、次のように書かれています。
Range の既定のメンバーは、パラメーターなしの呼び出しを Value プロパティに転送し、パラメーター付きの呼び出しを Item メンバーに転送します。 (Microsoft)
つまり、 rng が rng.Value と解釈されうるということです。
上のコードを振り返ってみましょう。
前提として v は Variant で宣言していますから、値もオブジェクトも代入できます。
Dim v As Variant ' 値もオブジェクトも代入できる
まずは Let です。 Let は右辺に値を期待します。
しかしながら rng はオブジェクトなので Let では扱えません。そこで rng を rng.Value と解釈してみると、これは値 (String) なので Let で扱えます。そのため v には rng.Value が代入されます。
Let v = rng ' 右辺は rng.Value (String) と解釈される
Debug.Print TypeName(v) ' -> String
次に Set です。 Set は右辺にオブジェクトを期待します。
rng はオブジェクト (Range) ですから、 v には rng が代入されます。
Set v = rng ' 右辺は rng (Range) と解釈される
Debug.Print TypeName(v) ' -> Range
このように Set キーワードの有無で挙動が変化するコードがあります。
Set の有無には、人間が判断しないといけない理由があったのです。
Discussion