В этом посте представлено полное руководство по использованию VBA Sub.
Если вам нужна краткая информация о создании VBA Sub, функции, передаче параметров, возвращаемых значениях и т. д., ознакомьтесь с кратким руководством ниже.
Если вы хотите понять все о подфункции VBA, вы можете прочитать статью от начала до конца или ознакомиться с оглавлением ниже.
Содержание
Краткое руководство по VBA Sub
Sub | Пример |
---|---|
Sub Невозможно вернуть значение. | |
Function Может возвращать значение или объект. Может выполняться как функция рабочего листа. | |
Создание процедуры Sub | Sub ТотСамыйКод() End Sub |
Создание функции | Function Итог() As Long End Function |
Создание процедуры Sub с оглашением параметров | Sub ТотСамыйКод(ByVal Цена As Double) Sub ТотСамыйКод(ByVal Имя As String) |
Создание процедуры Function с оглашением параметров | Function Итог(Цена As Double) Function Итог(Имя As String) |
Вызов процедуры Sub | Call MySub MySub |
Вызов процедуры Function | Call GetTotal GetTotal |
Вызов процедуры Sub с указанием параметров | Call MySub(12.99) MySub 12.99 |
Вызов процедуры Function с указанием параметров | Call GetTotal(12.99) GetTotal 12.99 |
Вызов процедуры Function и получение значения в переменную (для этого нельзя использовать ключевое слово Call) | Price = GetTotal |
Вызов функции и получение объекта | Set coll = GetCollection |
Вызов функции с параметрами и получение значения/объекта | Price = GetTotal(12) Set coll = GetCollection(“Apples”) |
Возврат значения из функции | Function GetTotal() As Long GetTotal = 67 End Function |
Возвращение объекта из функции | Function GetCollection() As Collection Dim coll As New Collection Set GetCollection = coll End Function |
Выход из процедуры Sub | If IsError(Range(“A1”)) Then Exit Sub End If |
Выход из процедуры Function | If IsError(Range(“A1”)) Then Exit Function End If |
Частная подфункция/частная функция (доступна для текущего модуля) | Private Sub MySub() Private Function GetTotal() |
Публичная подфункция/публичная функция (доступно для всего проекта) | Public Sub MySub() Public Function GetTotal() |
Введение
VBA Sub – это важный компонент языка VBA. Вы также можете создавать функции, которые очень похожи на sub. Они обе являются процедурами, в которых вы пишете свой код. Однако есть и различия, и их важно понимать. В этой заметке мы подробно рассмотрим subs и functions и ответим на важные вопросы, в том числе:
В чем разница между ними?
Когда использовать подфункцию, а когда функцию?
Как их запускать?
Могу ли я возвращать значения?
Как передавать им параметры?
Что такое необязательные параметры?
и многое другое
Давайте начнем с того, что рассмотрим, что такое подфункция в VBA?
Что такое подфункция?
В Excel VBA подпрограмма и макрос – это, по сути, одно и то же. Это часто приводит к путанице, поэтому нелишним будет запомнить это. В дальнейшем я буду называть их подпрограммами.
Подпрограмма/макрос – это место, куда вы помещаете строки кода VBA. Когда вы запускаете подпрограмму, выполняются все содержащиеся в ней строки кода. Это означает, что VBA выполняет их инструкции.
Ниже приведен пример пустого вложенного файла
Sub Exmpl()
End Sub
Вы объявляете подпрограмму, используя ключевое слово Sub и имя, которое вы хотите дать подпрограмме. Когда вы даете ему имя, имейте в виду следующее:
Имя должно начинаться с буквы и не должно содержать пробелов.
Имя должно быть уникальным в текущей рабочей книге.
Имя не может быть зарезервированным словом в VBA.
Конец Sub обозначается строкой End Sub.
Когда вы создадите Sub, вы можете добавить некоторый код, как показано в следующем примере:
Sub Exmpl()
Range("A1") = 6
End Sub
Что такое функция?
Функция очень похожа на подфункцию. Основное отличие заключается в том, что функция может возвращать значение, а подфункция – нет. Есть и другие различия, которые мы рассмотрим, но это главное.
Обычно вы создаете функцию, когда хотите вернуть значение.
Создание функции аналогично созданию подфункции
Добавление возвращаемого типа в функцию необязательно. Если вы не добавите тип, то по умолчанию это будет тип Variant. Это означает, что VBA определит тип во время выполнения.
В следующем примере показано, как указать возвращаемый тип
Function PerformCalc() As Long
End Function
Вы видите, как просто вы объявляете переменную. Вы можете вернуть любой тип, который вы можете объявить в качестве переменной, включая объекты и коллекции.
Вызов подфункции или функции
Когда люди только начинают работать с VBA, они стремятся поместить весь код в одну подфункцию. Это не лучший способ написания кода.
Лучше разбить код на несколько процедур. Мы можем запускать одну процедуру из другой.
Вот пример:
Sub Main()
' вызывать каждую процедуру для выполнения какого-то задания
CopyData
AddFormulas
FormatData
End Sub
Sub CopyData()
' Тут какой-то код
End Sub
Sub AddFormulas()
' Тут какой-то код
End Sub
Sub FormatData()
' Тут какой-то код
End Sub
На самом деле в VBA существует ключевое слово Call. Мы можем использовать его следующим образом:
Sub Main()
Call CopyData
Call AddFormulas
Call FormatData
End Sub
Использование ключевого слова Call необязательно. Нет никакой реальной необходимости использовать его, если только вы не новичок в VBA и не считаете, что оно делает ваш код более читабельным.
Если вы передаете аргументы с помощью Call, то вы должны использовать круглые скобки вокруг них.
Например:
Sub Main()
' Если вызов не используется, то скобки не нужны
AddValues 2, 4
' вызов требует круглых скобок для аргументов
Call AddValues(2, 4)
End Sub
Sub AddValues(x As Long, y As Long)
End Sub
Как вернуть значение из функции
Чтобы вернуть значение из функции, нужно присвоить значение имени функции. Следующий пример демонстрирует это:
Function GetAmount() As Long
' Возвращает 55
GetAmount = 55
Конец функции
Function GetName() As String
' Возвращает "Привет, мир!"
GetName = "Привет, мир!"
End Function
Когда вы возвращаете значение из функции, вам, очевидно, необходимо получить его в функции/подфункции, которая ее вызвала. Вы делаете это, присваивая вызов функции переменной. Это показано в следующем примере:
Sub WriteValues()
Dim Amount As Long
' Получение значения из функции GetAmount
Amount = GetAmount
End Sub
Function GetAmount() As Long
GetAmount = 55
End Function
Вы можете легко проверить возвращаемое значение с помощью функции Debug.Print. Она запишет значения в окно Immediate Window (View->Immediate window из меню или нажмите Ctrl + G).
Sub WriteValues()
' Печать возвращаемого значения в окне Immediate Window
Debug.Print GetAmount
End Sub
Function GetAmount() As Long
GetAmount = 55
End Function
Использование параметров и аргументов
Мы используем параметры, чтобы передавать значения от одной подфункции к другой.
Термины “параметры” и “аргументы” часто путают:
Параметр – это переменная в объявлении подфункции/функции.
Аргумент – это значение, которое вы передаете параметру.
Sub UsingArgs()
' Аргументом является 56
CalcValue 56
' Аргумент равен 34
CalcValue 34
End Sub
Sub CalcValue(ByVal amount As Long)
End Sub
Вот несколько важных моментов о параметрах:
У нас может быть несколько параметров.
Параметр передается с помощью ByRef или ByVal. По умолчанию используется ByRef.
Мы можем сделать параметр необязательным для пользователя.
Мы не можем использовать ключевое слово New в объявлении параметра.
Если тип переменной не используется, то параметр по умолчанию будет вариантом.
Формат параметров
Подфункции и функции используют параметры одинаково.
Формат оператора параметров следующий:
' Все переменные, кроме массивов
[ByRef/ByVal] As [Тип переменной]
' Необязательный параметр - может быть только базового типа
[Необязательный] [ByRef/ByVal] [Имя переменной] As <[Тип переменной] =
' Массивы
[ByRef][имя массива]() As [Тип переменной].
Вот несколько примеров объявления различных типов параметров:
‘ Основные типы
Sub UseParams1(count As Long)
End Sub
Sub UseParams2(name As String)
End Sub
Sub UseParams3(amount As Currency)
End Sub
' Коллекция
Sub UseParamsColl(coll As Collection)
End Sub
' Объект модуля класса
Sub UseParamsClass(o As Class1)
End Sub
' Вариант
' Если тип не указан, то это автоматически вариант
Sub UseParamsVariant(value)
End Sub
Sub UseParamsVariant2(value As Variant)
End Sub
Sub UseParamsArray(arr() As String)
End Sub
Вы видите, что объявление параметров похоже на использование оператора Dim для объявления переменных.
Множественные параметры
Мы можем использовать несколько параметров в наших под/функциях. Это может сделать строку очень длинной
Sub LongLine(ByVal count As Long, Optional amount As Currency = 56.77, Optional name As String = "John")
Мы можем разделить строку кода с помощью символа подчеркивания (_). Это делает наш код более читабельным
Sub LongLine(ByVal count As Long _
, Optional amount As Currency = 56.77 _
, Optional name As String = "John")
Параметры с возвращаемым значением
Эта ошибка вызывает много разочарований у начинающих пользователей VBA.
Если вы возвращаете значение из функции, то она должна иметь круглые скобки вокруг аргументов.
Приведенный ниже код выдаст синтаксическую ошибку “Expected: end of statement”.
Sub UseFunction()
Dim result As Long
result = GetValue 24.99
End Sub
Function GetValue(amount As Currency) As Long
GetValue = amount * 100
End Function
Мы должны написать это следующим образом
result = GetValue (24.99)
ByRef и ByVal
Каждый параметр является либо ByRef, либо ByVal. Если тип не указан, то по умолчанию это ByRef.
' Передача по значению
Sub WriteValue1(ByVal x As Long)
End Sub
' Передача по ссылке
Sub WriteValue2(ByRef x As Long)
End Sub
' Тип не используется, поэтому это ByRef
Sub WriteValue3(x As Long)
End Sub
Если вы не указали тип, то типом будет ByRef, как вы можете видеть в третьем примере.
Разница между этими типами заключается в следующем:
ByVal – создает копию переданной вам переменной.
Это означает, что если вы измените значение параметра, то оно не изменится при возвращении в вызывающую подфункцию/функцию.
ByRef – Создает ссылку на передаваемую переменную.
Это означает, что если вы измените значение переменной параметра, оно будет изменено при возвращении к вызывающей подфункции.
Следующий пример кода показывает это:
Sub Test()
Dim x As Long
' Передача по значению - x не изменится
x = 1
Debug.Print "x before ByVal is"; x
SubByVal x
Debug.Print "x after ByVal is"; x
' Передача по ссылке - x изменится
x = 1
Debug.Print "x before ByRef is"; x
SubByRef x
Debug.Print "x после ByRef is"; x
End Sub
Sub SubByVal(ByVal x As Long)
' x НЕ ИЗМЕНЯЕТСЯ вне переданного значения ByVal
x = 99
End Sub
Sub SubByRef(ByRef x As Long)
' x БУДЕТ изменяться снаружи по мере передачи ByRef
x = 99
End Sub
Результатом этого является:
x до ByVal равен 1
x после ByVal равен 1
x перед ByRef равен 1
x после ByRef равен 99
Вам следует избегать передачи базовых типов переменных с помощью ByRef. Для этого есть две основные причины:
Человек, передающий значение, может не ожидать, что оно изменится, и это может привести к ошибкам, которые трудно обнаружить.
В качестве заключения
Надеюсь, что вам была полезна эта статья, продолжение этой тематики будет в следующих статьях.