🐡

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)

つまり、 rngrng.Value と解釈されうるということです。

上のコードを振り返ってみましょう。
前提として vVariant で宣言していますから、値もオブジェクトも代入できます。

Dim v As Variant ' 値もオブジェクトも代入できる

まずは Let です。 Let は右辺に値を期待します。
しかしながら rng はオブジェクトなので Let では扱えません。そこで rngrng.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