Разбираем области видимости, Set и константы в VBA

Разберем три важные темы в VBA: области видимости процедур и функций, оператор Set и константы. С кодом, примерами и выводами.

1. Области видимости процедур и функций в VBA

По умолчанию: Private или Public?

По умолчанию все процедуры и функции в VBA являются Public.

Это означает, что если вы не укажете ключевое слово Private или Public при объявлении, процедура будет доступна для вызова из любого модуля в рамках текущего проекта. Исключение составляют только процедуры событий (например, Worksheet_Change или CommandButton_Click), которые VBA автоматически создает с ключевым словом Private.

Важно различать это правило для процедур и для переменных уровня модуля: переменные, объявленные с помощью Dim в секции объявлений (вне процедур), по умолчанию имеют область видимости Private.

Можно ли изменить это правило в настройках?

Глобальной настройки, которая меняла бы поведение по умолчанию для всех процедур во всех проектах, в VBA не существует. Однако вы можете управлять областью видимости, используя следующие подходы:

  • Явное указание ключевого слова: Самый простой способ — всегда явно писать Public или Private перед объявлением процедуры или функции. Это делает код однозначным.
  • Директива Option Private Module: Это не глобальная настройка, а специальный оператор, который добавляется в секцию объявлений конкретного модуля. Если вы добавите Option Private Module в начало модуля, то все процедуры в этом модуле, даже объявленные как Public, станут доступны только внутри текущего проекта и будут скрыты от других проектов, которые ссылаются на ваш. Это полезно для создания внутренних библиотек.
  • Объектные модули: В модулях, связанных с объектами (например, модули листов, книг, форм), директива Option Private Module действует по умолчанию. Это означает, что их публичные процедуры также не видны извне проекта. Изменить это поведение через код нельзя.

Краткий итог

Уровень

Правило по умолчанию

Как изменить

Процедуры и функции

Public

(кроме процедур событий)

Явно указать

Private

при объявлении.

Область видимости модуля

Public

(виден всем проектам)

Добавить

Option Private Module

в секцию объявлений модуля, чтобы скрыть его содержимое от других проектов.

Глобальная настройка

Отсутствует

Нет. Управление осуществляется только на уровне кода.

2. Set внутри функции / процедуры

Что это?

Set в VBA — это не объявление множества (как set в Python) и не контейнер.
Set — это ключевое слово-оператор, которое используется для присваивания объектной переменной ссылки на объект.

То есть:

  • Dim — объявляет переменную.
  • Set — присваивает объектной переменной ссылку на объект.
  • Let — присваивает значение (в современном VBA почти всегда опускается).
  • New — создаёт новый объект.

Пример

vba

Sub SetExample()
    Dim ws As Worksheet
    Dim rng As Range
    Dim coll As Collection
    
    ' Set присваивает ссылку на объект
    Set ws = ThisWorkbook.Worksheets("Лист1")
    Set rng = ws.Range("A1:B10")
    Set coll = New Collection
    
    coll.Add "значение"
    rng.Value = 1
    
    ' Явное освобождение ссылки
    Set ws = Nothing
    Set rng = Nothing
    Set coll = Nothing
End Sub

Без Set для объектов будет ошибка:

vba

Dim ws As Worksheet
ws = ThisWorkbook.Worksheets(1)   ' Ошибка 91: Object variable not set

Правильно:

vba

Set ws = ThisWorkbook.Worksheets(1)

Для простых типов Set не нужен:

vba

Dim x As Long
x = 10          ' значение
' Set x = 10    ' ошибка

Кратко

Ключевое слово

Назначение

Пример

Dim

Объявление переменной

Dim x As Long

Set

Присвоить ссылку на объект

Set rng = Range("A1")

Let

Присвоить значение (необязательно)

Let x = 5

New

Создать новый объект

Set coll = New Collection

Почему перед переменной внутри процедуры стоит Dim?

Dim — сокращение от Dimension.
В старом BASIC DIM использовался для объявления массивов и указания их размерности. Позже его расширили на объявление любых переменных.

В VBA Dim не означает, что переменная обязательно живёт только внутри процедуры.
Dim просто объявляет переменную. А её область видимости и время жизни зависят от места объявления и модификатора.

Где объявлена переменная — там и область видимости

vba

' Секция объявлений модуля
Dim moduleVar As Long          ' уровень модуля, доступна всем процедурам модуля

Sub Test()
    Dim localVar As Long       ' локальная, только внутри Test
    Static staticVar As Long   ' локальная, но сохраняет значение между вызовами
    
    localVar = localVar + 1
    staticVar = staticVar + 1
    moduleVar = moduleVar + 1
    
    Debug.Print localVar, staticVar, moduleVar
End Sub

Если вызвать Test несколько раз:

  • localVar каждый раз будет начинаться с 0 и станет 1.
  • staticVar будет увеличиваться: 1, 2, 3, …
  • moduleVar тоже будет увеличиваться, пока модуль загружен.

Область видимости

Где объявлено

Ключевое слово

Видимость

Время жизни

Внутри процедуры

Dim

Только внутри этой процедуры

Пока процедура выполняется

Внутри процедуры

Static

Только внутри процедуры

Между вызовами процедуры

В секции объявлений модуля

Dim

или

Private

Внутри модуля

Пока модуль загружен

В секции объявлений модуля

Public

Из других модулей проекта

Пока проект загружен

То есть Dim внутри процедуры действительно делает переменную локальной.
Но сам Dim — это просто объявление, а не «указание на локальность».

Что происходит с переменной после выхода из процедуры?

Когда процедура/функция завершается:

  • Локальные переменные простых типов (Long, String, Double и т.п.) уничтожаются, память освобождается.
  • Локальные объектные переменные (Worksheet, Range, Collection и т.п.) теряют ссылку на объект.
  • Если на объект больше нет других ссылок, объект уничтожается.
  • Если другие ссылки есть, объект продолжает жить.

Про «сборщик мусора»

В VBA нет сборщика мусора в том смысле, как в Java, C# или Python.
VBA/COM использует подсчёт ссылок:

  • Каждая объектная переменная увеличивает счётчик ссылок на объект.
  • Когда переменная выходит из области видимости или ей присваивают Nothing, счётчик уменьшается.
  • Когда счётчик становится равен 0, объект уничтожается сразу.

Пример:

vba

Sub Demo()
    Dim coll As Collection
    Set coll = New Collection
    coll.Add "test"
    ' При выходе из Demo переменная coll исчезает.
    ' Если других ссылок на Collection нет, объект уничтожается.
End Sub

Явно освободить ссылку можно так:

vba

Set coll = Nothing

Важный нюанс: циклические ссылки

Поскольку это подсчёт ссылок, а не трассирующий сборщик мусора, циклические ссылки могут не освобождаться автоматически.
Например, объект A ссылается на B, а B ссылается на A. Даже если внешних ссылок нет, счётчики не обнулятся. В VBA такие объекты могут остаться в памяти до сброса проекта (Run → Reset) или закрытия приложения.

Итог по Set и Dim

  1. Set — это не контейнер и не объявление множества, а оператор присваивания ссылки на объект.
  2. Dim — это объявление переменной, от слова Dimension. Оно не «подчёркивает локальность», а просто объявляет переменную. Локальность определяется тем, что Dim стоит внутри процедуры.
  3. После выхода из процедуры локальные переменные уничтожаются. Для объектов работает подсчёт ссылок COM, а не классический сборщик мусора. Циклические ссылки могут не освобождаться до сброса проекта.

3. Константы в VBA

Что такое константа

Константа — это именованная величина, значение которой задаётся один раз при объявлении и не может быть изменено во время выполнения программы. Попытка присвоить константе новое значение вызовет ошибку компиляции.

Объявляется с помощью ключевого слова Const (от англ. constant — постоянная).

vba

Const PI As Double = 3.14159265358979

После этого строка PI = 3.14 вызовет ошибку: "Assignment to constant not permitted".

Где можно объявлять константы

Как и переменные, константы можно объявлять на трёх уровнях. Но, в отличие от переменных, у констант есть важное ограничение: значение должно быть известно на этапе компиляции (литерал или выражение из других констант).

1. Локальные константы — внутри процедуры/функции

Видны только внутри этой процедуры. Живут, пока выполняется процедура.

vba

Sub CalculateCircle()
    Const PI As Double = 3.14159265358979
    Dim r As Double
    Dim area As Double
    
    r = 5
    area = PI * r ^ 2
    
    Debug.Print "Площадь круга: " & area
End Sub

2. Константы уровня модуля — в секции объявлений модуля

Видны всем процедурам данного модуля. По умолчанию — Private.

vba

' Секция объявлений модуля (вверху)
Const MAX_RETRIES As Long = 3
Const APP_NAME As String = "Моё приложение"

Sub Procedure1()
    Debug.Print APP_NAME          ' доступна
    Debug.Print MAX_RETRIES       ' доступна
End Sub

Sub Procedure2()
    Debug.Print APP_NAME          ' тоже доступна
End Sub

3. Публичные константы — Public Const в секции объявлений

Видны из всех модулей проекта.

vba

' В модуле с именем modConstants
Public Const TAX_RATE As Double = 0.2
Public Const COMPANY_NAME As String = "ООО Ромашка"

vba

' В другом модуле
Sub ShowTax()
    Dim price As Double
    price = 1000
    Debug.Print "Цена с налогом: " & price * (1 + TAX_RATE)
End Sub

Аналог из старых версий Basic — Global Const. В VBA Global оставлен для совместимости, но использовать нужно Public.

Сводная таблица по областям видимости

Где объявлена

Ключевое слово

Видимость

Время жизни

Внутри процедуры

Const

Только внутри процедуры

Пока процедура выполняется

Секция объявлений модуля

Const

или

Private Const

Все процедуры модуля

Пока модуль загружен

Секция объявлений модуля

Public Const

Все модули проекта

Пока проект загружен

Чем константа отличается от переменной

Свойство

Переменная (

Dim

)

Константа (

Const

)

Значение можно менять

Да

Нет

Можно задать во время выполнения

Да

Нет, только на этапе компиляции

Можно присвоить объект через

Set

Да

Нет

Можно использовать в качестве параметра

ByRef

Да

Нет (только

ByVal

)

Может быть массивом

Да

Нет (нельзя

Const arr(1 To 5)

)

Может быть пользовательским типом (

Type

)

Да

Нет (нельзя

Const x As MyType

)

Что можно присваивать константе

Только литералы или выражения из других констант:

vba

Const A As Long = 10
Const B As Long = A * 2          ' OK — выражение из констант
Const C As Long = A + SomeFunc() ' Ошибка — вызов функции не допускается
Const D As String = "Привет"     ' OK
Const E As Date = #1/1/2025#     ' OK
Const F As Double = 1 / 3        ' OK — арифметика

Примеры использования

Пример 1: Замена «магических чисел»

Плохо:

vba

Sub BadCode()
    Dim discount As Double
    discount = price * 0.07   ' что такое 0.07? непонятно
End Sub

Хорошо:

vba

Const VAT_RATE As Double = 0.07

Sub GoodCode()
    Dim discount As Double
    discount = price * VAT_RATE
End Sub

Пример 2: Общие настройки приложения

vba

' modConfig
Public Const APP_TITLE As String = "Учёт заявок"
Public Const DB_PATH As String = "C:\Data\base.accdb"
Public Const MAX_ROWS As Long = 10000
Public Const SUPPORT_EMAIL As String = "support@example.com"

Теперь во всех модулях используется единый источник значений. Изменить настройку можно в одном месте.

Пример 3: Константы для цветов и шрифтов

vba

Public Const COLOR_HEADER As Long = &H4F81BD      ' синий
Public Const COLOR_WARNING As Long = &HFF0000     ' красный (BGR)
Public Const FONT_MAIN As String = "Calibri"

Sub FormatHeader(rng As Range)
    With rng
        .Interior.Color = COLOR_HEADER
        .Font.Name = FONT_MAIN
        .Font.Bold = True
    End With
End Sub

Пример 4: Локальная константа для читаемости

vba

Function DaysInYear(year As Long) As Long
    Const DAYS_IN_NORMAL_YEAR As Long = 365
    Const DAYS_IN_LEAP_YEAR As Long = 366
    
    If IsLeapYear(year) Then
        DaysInYear = DAYS_IN_LEAP_YEAR
    Else
        DaysInYear = DAYS_IN_NORMAL_YEAR
    End If
End Function

Пример 5: Константы в условиях

vba

Public Const ENV_PROD As String = "PROD"
Public Const ENV_TEST As String = "TEST"

Sub Connect(env As String)
    Select Case env
        Case ENV_PROD
            ' подключение к боевой БД
        Case ENV_TEST
            ' подключение к тестовой БД
        Case Else
            MsgBox "Неизвестное окружение"
    End Select
End Sub

Особый случай: #Const — условная компиляция

Это отдельный вид констант, которые используются только на этапе компиляции и позволяют включать/выключать блоки кода:

vba

#Const DEBUG_MODE = True

Sub Test()
    #If DEBUG_MODE Then
        Debug.Print "Отладочный вывод"
    #End If
End Sub

Эти константы не являются обычными Const и живут по другим правилам — их можно переопределять на уровне проекта (в свойствах проекта → Условная компиляция).

Лучшие практики

  1. Не используйте «магические числа» — выносите их в константы.
  2. Группируйте константы в отдельном модуле (modConstants) для удобства.
  3. Давайте осмысленные имена — VAT_RATE лучше, чем V.
  4. Указывайте тип — Const X As Double = 3.14, а не просто Const X = 3.14.
  5. Используйте Public Const только когда константа реально нужна другим модулям — иначе Private или локальная.
  6. Помните про ограничения: нельзя Const для объектов, массивов, пользовательских типов и значений, вычисляемых во время выполнения.

Итог по константам

  • Константа — это именованная неизменяемая величина, объявляемая через Const.
  • Может быть локальной (внутри процедуры), модульной (Const/Private Const в секции объявлений) и публичной (Public Const).
  • Значение должно быть известно на этапе компиляции.
  • Нельзя объявлять константами объекты, массивы и пользовательские типы.
  • Основное назначение — убрать «магические числа», централизовать настройки и повысить читаемость кода.
  • Отдельно существует #Const — для условной компиляции, это другая сущность.

Общий итог

Мы разобрали три ключевые темы VBA:

  1. Области видимости процедур и функций: по умолчанию Public, кроме событий. Управлять можно явным указанием Private/Public и директивой Option Private Module. Глобальной настройки нет.
  2. Оператор Set и Dim: Set присваивает ссылку на объект, Dim объявляет переменную. Dim не делает переменную локальной — это зависит от места объявления. После выхода из процедуры локальные переменные уничтожаются, объекты освобождаются через подсчёт ссылок COM (возможны циклические ссылки).
  3. Константы: объявляются через Const, неизменяемы, могут быть локальными, модульными и публичными. Значение должно быть известно на этапе компиляции. Помогают избежать «магических чисел» и централизовать настройки. Отдельно есть #Const для условной компиляции.

Используйте эти знания, чтобы писать более чистый, понятный и надёжный код на VBA.

1 view