この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: 変数宣言時のSETありなしの違い
SEOタイトル: VBA Set ステートメント (オブジェクト変数) 完全ガイド

この記事の要点
  • VBA ではオブジェクト変数への代入時に Set が必須Set rng = Range("A1")
  • プリミティブ型 (Integer / Long / String / Double / Boolean / Date) は Set 不要
  • Set を忘れると 「Object Required」「実行時エラー 91」「実行時エラー 424」が出る
  • オブジェクト解放は Set obj = Nothing
  • Let キーワードは値型代入用で省略可能 (デフォルト)。現代は省略が標準

VBA における代入の 2 種類

VBA (Visual Basic for Applications) では代入が値の代入オブジェクト参照の代入で構文が分かれます。

代入の種類構文対象
値の代入[Let] x = 値Integer, Long, String, Double, Boolean, Date, Variant (中身が値)
オブジェクト参照Set obj = オブジェクトRange, Worksheet, Workbook, Collection, ユーザ定義クラス

プリミティブ型: Set なし

Sub PrimitiveExample()
    Dim n As Integer
    Dim s As String
    Dim d As Double
    Dim b As Boolean
    Dim dt As Date

    n = 10              ' ✅ Set 不要
    s = "Hello"
    d = 3.14
    b = True
    dt = #2026/06/10#

    ' Let を明示することも可能 (省略推奨)
    Let n = 20
End Sub

オブジェクト型: Set 必須

Sub ObjectExample()
    Dim rng As Range
    Dim ws As Worksheet
    Dim wb As Workbook
    Dim col As Collection

    ' ✅ オブジェクトは Set 必須
    Set rng = Range("A1:B10")
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    Set wb = Workbooks.Open("C:\data.xlsx")
    Set col = New Collection

    ' ❌ Set を忘れると…
    ' rng = Range("A1:B10")   ' 実行時エラー 91 / Object Required
End Sub

Set を忘れたときのエラー

エラー番号メッセージ状況
91オブジェクト変数または With ブロック変数が設定されていませんSet し忘れて使った
424オブジェクトが必要ですSet 必須なところで Set を省略
438オブジェクトは、このプロパティまたはメソッドをサポートしていません型が違うものを代入
13型が一致しませんオブジェクトに値を代入しようとした

典型的なミスと対処

' ❌ よくある間違い 1: Range を Set なしで取る
Dim rng As Range
rng = Range("A1")               ' 実行時エラー 91

' ✅ 正解
Dim rng As Range
Set rng = Range("A1")

' ❌ よくある間違い 2: Worksheet を Set なし
Dim ws As Worksheet
ws = Worksheets("Sheet1")       ' エラー 91 or 13

' ✅ 正解
Set ws = Worksheets("Sheet1")

' ❌ Cells に値を代入するつもりが Set
Set rng.Value = 100             ' エラー 438
                                ' Value はプロパティ (値型) なので Set 不可

' ✅ 正解
rng.Value = 100

なぜ Set が必要か (内部動作)

オブジェクト変数はオブジェクトへの参照 (ポインタ相当) を保持します。Set は「参照を更新せよ」という宣言で、これがないと VBA は「左辺のデフォルトプロパティに値を代入しろ」と解釈してしまいます。

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1")
Set rng2 = rng1                  ' rng2 も同じセル A1 を指す (参照コピー)

rng1.Value = 100
Debug.Print rng2.Value           ' → 100 (同じセル)

Set rng2 = Range("B1")           ' rng2 だけ B1 を指す
Debug.Print rng1.Address         ' $A$1 (rng1 は変わらない)

' Range のデフォルトプロパティが Value なので
rng1 = Range("B1")               ' = rng1.Value = Range("B1").Value
                                 ' → A1 セルに B1 の値が入る (代入とは別の動作!)

オブジェクトの解放: Set Nothing

巨大なオブジェクト (Workbook / 外部 COM オブジェクト) は使い終わったら Set ... = Nothing で参照を切るとメモリ解放を促せます (VBA は参照カウント方式)。

Sub OpenAndClose()
    Dim wb As Workbook
    Set wb = Workbooks.Open("C:\big.xlsx")

    ' 処理...

    wb.Close SaveChanges:=False
    Set wb = Nothing             ' 明示的に解放
End Sub

' COM オブジェクト (Excel から Word を呼ぶ等)
Sub WordExport()
    Dim wordApp As Object
    Set wordApp = CreateObject("Word.Application")
    wordApp.Visible = True

    ' 処理...

    wordApp.Quit
    Set wordApp = Nothing         ' ★ 解放しないと Word プロセス残存
End Sub

New キーワードとの組み合わせ

' クラスのインスタンス化
Dim col As Collection
Set col = New Collection
col.Add "apple"
col.Add "banana"

' 宣言時 New (推奨されないことがある)
Dim col2 As New Collection      ' 初回アクセス時に自動 New
col2.Add "x"                    ' この時点で内部 New

' Dictionary (要参照設定: Microsoft Scripting Runtime)
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
dict.Add "key1", "value1"

With ステートメントとの組み合わせ

同じオブジェクトに何度もアクセスする場合は With で簡潔に:

' ❌ 冗長
Range("A1").Value = 100
Range("A1").Font.Bold = True
Range("A1").Interior.Color = vbYellow
Range("A1").Borders.LineStyle = xlContinuous

' ✅ With で簡潔に (内部的に同じオブジェクト参照を使い回す)
With Range("A1")
    .Value = 100
    .Font.Bold = True
    .Interior.Color = vbYellow
    .Borders.LineStyle = xlContinuous
End With

' Set + With の組み合わせ
Dim rng As Range
Set rng = Worksheets("Sheet1").Range("A1:B10")
With rng
    .ClearContents
    .Font.Name = "Meiryo"
End With

Let キーワード (歴史的経緯)

Let は値型代入の明示で、VB の祖先 BASIC の名残です。VBA では常に省略可能で、現代のコードでは書きません。

Let n = 10        ' 動くが古臭い
n = 10            ' 現代スタイル

' クラス側で Property Let / Property Set を定義する場合は別の話
Public Property Let Name(value As String)   ' 値型プロパティ setter
    m_name = value
End Property

Public Property Set Owner(value As Worksheet)  ' オブジェクト型プロパティ setter
    Set m_owner = value
End Property

Variant 型の挙動

Dim v As Variant

v = 100              ' 値として代入 → Variant/Integer
v = "Hello"          ' 文字列再代入 → Variant/String

Set v = Range("A1")  ' オブジェクト代入 → Variant/Object
                     ' Set 必須 (オブジェクトを入れる時)

' Variant は便利だが型エラーが実行時まで分からない欠点あり
' 可能なら明示型を使う

FAQ

Q: 構造体 (Type) は Set 必要?
A: Type で定義したユーザ定義型は値型扱いなので Set 不要。Dim p As MyType: p = otherP で OK。

Q: 配列代入は?
A: 配列は値型なので Set 不要。arr1 = arr2 で要素ごとコピー。

Q: Set を間違って書くと?
A: Set n = 10 はエラー 13 (型不一致)。値型に Set はできません。