[Excel VBA]代入ステートメント Set/Letについて

VBAを始めたばかりの頃、「オブジェクト変数またはWithブロック変数が設定されていません」や「オブジェクトが必要です」のエラーダイアログに怒られっぱなしだったのをよく覚えています。怒られなくなったのはこの代入ステートメントが理解できたからだと思います。

目次

1行に1ステートメント

本題とは少しそれますが、Microsoft OfficeVBAリファレンスからの引用です。

ステートメント

1 種類の処理、宣言、または定義を表す、構文的に完全な単位。 通常では 1 行に 1 ステートメントですが、コロン (:) を使用することで 1 行に複数のステートメントを記述できます。 また、行連結文字 (_) を使用することにより、論理的な 1 行を物理的な複数行に継続できます。

https://docs.microsoft.com/ja-jp/office/vba/language/glossary/vbe-glossary#statement
適当なサンプルです。
Sub Demo1()
    Dim myVar As String: myVar = "悟空"
    MsgBox ("オッス!おら " & _
           myVar)
End Sub
このサンプルを「11ステートメント」に直すと以前の私だとこうなります。
Sub Demo2()
    Dim myVar As String
    myVar = "悟空"
    MsgBox ("オッス!おら " & myVar)
End Sub
これでも間違いではないのですが、理解が足りていない部分があります。厳密にはこうです。
Sub Demo3()                             'Subステートメント
    Dim myVar As String                 'Dimステートメント
    Let myVar = "悟空"                   'Letステートメント
    Call MsgBox ("オッス!おら " & myVar) 'Callステートメント
End Sub                                 'Endステートメント

これで「11ステートメント」になります。VBEのデフォルト設定だとステートメントは青文字で表示されます(このページだと緑)。11ステートメントが基本なのに、先頭が青文字にならない行があったのは「省略していたから」です。

特にこのLetステートメント、省略することが作法のようで、今までWeb上から拾ってきたサンプルに記述されていたことはありませんでした。サンプルから学ぶスタイルだと、なかなかLetステートメントに出会えないようです。

このLetステートメントを省略している事が分かると、Setステートメントの理解が早まると思います。

代入ステートメント

OfficeVBAリファレンスを覗くとステートメントについて以下のような説明があります。

Visual Basic のステートメントは完結した命令です。 ステートメントにはキーワード、演算子、変数、定数、および式を含めることができます。 各ステートメントは次の 3 つのカテゴリのいずれかに属します。

変数、定数、またはプロシージャの名前を指定し、データ型を指定できる宣言ステートメント。

変数または定数に値または式を割り当てる割り当てステートメント

アクションを開始する実行可能ステートメント。 これらのステートメントは、メソッドまたは関数を実行し、コード ブロックをループまたは分岐できます。 多くの場合、実行可能ステートメントには算術演算子または条件付き演算子が含まれます。

https://docs.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/writing-visual-basic-statements

本項は「変数または定数に値または式を割り当てる割り当てステートメント」のお話です。 LetSetのお話です。

サンプルを例に説明します。

demo4を実行するとA1セルに入力されている文字列がダイアログで表示されます。
Sub demo4()
    Dim myVar As String
    myVar = Range("A1")
    MsgBox (myVar)
End Sub
省略せずに記述すると以下の通りです。Letステートメントで値を代入しています。ただし省略可能かつ省略推奨(公式より)なので、普段このような記述を見かけることはありません。
Sub demo5()
    Dim myVar As String
    Let myVar = Range("A1").Value
    Call MsgBox(myVar)
End Sub
今度は変数の型をオブジェクト型(Range)にしてみます。Valueプロパティをしれっと消しているのは話が脱線するからです。このマクロは「オブジェクト変数またはWithブロック変数が設定されていません」 エラーが出ます。原因はLetステートメントです。
Sub demo6()
    Dim myVar As Range
    Let myVar = Range("A1")  'エラー
    Call MsgBox(myVar)
End Sub
値ではなくオブジェクトを代入するときはSetステートメントを使います。
Sub demo7()
    Dim myVar As Range
    Set myVar = Range("A1")
    Call MsgBox(myVar)
End Sub

Setステートメントを使用してオブジェクトをオブジェクトとして宣言された変数に代入します。

https://docs.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/writing-assignment-statements

「オブジェクトとして宣言された変数」に注目です。「代入するものがオブジェクトかどうか」もSet/Letどちらを使うかの判断材料になりますが、「宣言された変数の型がオブジェクト型かどうか」も同じく判断材料になります。特にRangeオブジェクトって難しいですよね?代入するもので判断できないときは変数の型に注目してみて下さい。

今回のサンプルでは、代入するものはRange(“A1”)ですが、ここで判断しなくても変数がオブジェクト型かどうか(Range型はオブジェクト型)で判断できます。

ちなみにこのサンプル、Variant型で宣言するとSet/Let(省略)のどちらでもエラーは出ません。

プロパティの値を代入するのはLetステートメントです。もちろん省略可能です。
Sub demo8()
    Dim myVar As Range
    Set myVar = Range("A1")
    Let myVar.Font.Bold = True
End Sub

Setステートメントについて、個人的に理解が遅れていた部分を紹介しました。Web上でサンプルを拾ってつつきまわして挙動を見て、みたいな学習方法だったので基礎知識は後回しになっていました。基礎知識先行で頭でっかちになるのも嫌ですが、やはりバランスは必要です。

行き詰ったら基礎をおさらいしましょう(戒め)。

それでは、最後までご高覧いただきありがとうございました。

目次
閉じる