Return to VBA Code Examples
This tutorial will demonstrate how to use structures in VBA.
A structure in VBA is essentially a user-defined data type. When we use variables in VBA, we can declare them a string variable, number variables etc. Creating a structure essentially creates a new variable type, the structure itself can contain multiple data types. Many uses of Excel use class modules instead of structures but that can mean you end up with an unnecessary amount of individual class modules.
Defining a Structure
A structure begins with the word Type and ends with End Type.
Type Customer
CustName As String
CustPhone As String
CustAddress As String
CustRep As String
End Type
To use this structure within a procedure, we can do as follows:
Sub CustTest ()
Dim strC As Customer
strC.CustName = "Fred Jones"
strC.CustAddress = " 123 Oak Lane, Cleveland"
strC.CustPhone = "4589341"
strC.CustRep = "Jim"
End Sub
Where a type is essentially a way of grouping variables together that are all related to each other, such as the customer details above.
A structure needs to be stored in a module and needs to be at the top of the module where module variables would be stored.
A structure cannot be stored in a class module or form module – if you were to store the type in the class module and then tried to call the type from a module or even from within that class, you would end up with an error occurring.
Using a Structure to get Data from a Range
In our workbook, we have the following data table:
We can now create a structure in a new module to store the Employee Name, Age and Job Description.
Type Employees
EmpName As String
EmpAge As Integer
EmpJob As String
End Type
We can now create a routine to loop through a range in Excel and populate the type with multiple employees.
Sub GetEmployees ()
Dim Employee() As Employees
Dim i As Integer
ReDim Employee(10)
For i = 0 To 9
Employee(i).EmpName = Range("B" & i + 2)
Employee(i).EmpAge = Range("C" & i + 2)
Employee(i).EmpJob = Range("D" & i + 2)
Next i
'show in immediate window
For i = 0 To 9
Debug.Print (Employee(i).EmpName & " is " & Employee(i).EmpAge & " old and is employed as a " & Employee(i).EmpJob)
Next i
End Sub
First we declare a variable array as an Employees variable. We then size the array and loop through a range of cells in an Excel workbook to populate the array. We then output the results to the debug (immediate) window.
Nested Structures
Consider the following structures:
Now, lets as a third structure below these 2:
Type Invoice
InvRep As Employees
InvCust As Customer
End Type
Where the InvRep variable has been defined as being an Employees variable type, while the InvCust variable has been defined as being an Customer variable type.
We can therefore drill down in our procedure to populate some variables.
When we create our procedure, a drop down list will appear showing the variables available in each type.
We can therefore populate our variables as shown in the following procedure below:
Sub GetInfo()
Dim strInv As Invoice
strInv.InvCust.CustName = "Bob Smith"
strInv.InvCust.CustAddress = "123 Oak Lane, Cleveland"
strInv.InvRep.EmpName = "Fred Lindburgh"
strInv.InvRep.EmpJob = "Sales Manager"
End Sub
VBA Coding Made Easy
Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
Learn More!
Содержание:
-
Введение
-
Учебная задача
-
Типы простых структур данных в VBA
-
Методика тестирования
-
Описание структур
-
Структура DA1S
-
Структура DA2S
-
Структура DA2V
-
Структура CA2V
-
Структура A2A2V
-
Структура A2A2A1V
-
Структура A1UU
-
Структура DDA1V
-
Структура DDC
-
Сравнительный анализ
-
Файл проекта
-
Итоговые рекомендации
Введение
В процессе решения практических задач на языке программирования VBA неизбежно возникает потребность размещать в памяти компьютера структуры данных, обращаться к ним, манипулировать ими. В целом VBA справляется с этой задачей хорошо. За исключением традиционных претензий к VB по поводу отсутствия указателей и средств прямого управления памятью, отсутствие которых обусловлено тем, что создатели языка намеренно хотели оградить программиста от подобной активности с целью роста продуктивности работы (среда берёт на себя все мелкие нюансы управления памятью в процессе объявления и использования структур), в остальном имеющиеся в VBA стредства вполне адекватны ожиданиям.
Основная причина, которая вынуждает VBA программиста размещать данные в оперативной памяти, а, скажем, не в таблицах Excel, — это необходимость обрабатывать большие объёмы информации с максимально возможной скоростью. Объекты, типа Range не могут обеспечить необходимой скорости в виду своей сложности и громоздкости. Любая операция с ячейкой рабочего листа занимает больше времени, чем операция с переменной в памяти. В виду этого, VBA программист должен уметь проектировать структуры данных, знать средства, которыми для этого располагает язык и знать слабые и сильные стороны разных подходов к созданию структур.
▲ вверх
Учебная задача
В этом исследовании мы рассмотрим 9 разных способов реализации одной единственной структуры данных, измерим производительность, которую система демонстрирует с этими реализациями, выберем победителя. Нам необходимо реализовать следующую модельную структуру:
То есть у нас есть массив из N элементов (N считается неизвестным), каждый из которых в свою очередь является массивом из M элементов (M фиксировано и у нас =20), а те делятся ещё на 3 части с типами: double, long и string. Всего N*20*3 конечных элемента. Для доступа к массиву на первом уровне используются строковые ключи длиной 10 символов, для доступа к элементам массива на втором уровне используются ключи длиной 5 символов. Длина строки на третьем уровне 20 символов.
▲ вверх
Структура | Описание |
Строка с разделителями (String with delimeters) | Любая строка может служить контейнером для необходимого количества переменных строкового или числовых типов. Например, строка «ABCD123;123.45;789;» содержит в себе 4 элемента: строка ABCD123, вещественное число 123.45, целое число 789 и пустую строку. Работать с таким контейнером довольно хлопотно, но в то же время и ничего сложного. |
Фиксированный массив (Fixed array) | Массив, как известно, это последовательность определенного количества однотипных элементов. В случае фиксированного массива, количество элементов известно уже на этапе объявления массива. В качестве элементов массива может быть что угодно: числа, строки, логический тип, дата-время, пользовательский тип, а также тип variant, что допускает в качестве элементов и другие массивы или объекты. |
Динамический массив (Dynamic array) | Массив, для которого справедливо всё то, что сказано по поводу фиксированного массива, за исключением того, что количество его элементов может меняться в процессе исполнения программы. Для этого существует специальный оператор ReDim. Надо сказать, что это очень удобно и полезно, так как в большинстве случаев программист не может знать размеры необходимого ему массива, а объявлять огромные фиксированные массивы ужасный моветон. |
Пользовательский тип данных (User Data Type) | Этот тип позволяет объявить контейнер, который будет иметь внутреннюю структуру. Тип напоминает запись базы данных (например, в Pascal такой тип так и называется — record). Данный тип данных позволяет разложить всё по полочкам. Он удобен и интуитивно понятен. |
Коллекция (Collection) | Это объектный тип. Позволяет создать коллецию элементов. Каждому элементу во время добавления в коллекцию можно поставить в соответствие ключ (key), по которому потом удобно осуществлять доступ к самомму элементу (item). В целом полезен, если бы не было альтернативы в виде типа Dictionary, который перекрывает возможности Collection и по функционалу и по быстродействию. В качестве item (полезной нагрузки) допускает всё что угодно, кроме пользовательского типа. |
Словарь (Dictionary) |
Тоже объектный тип. Умеет всё то же, что и Collection, и дополнительно:
|
Класс (Class) | Чтобы подружить некое подобие UDT со словарями и коллекциями, применяют класс. Понятие класса слишком обширное, чтобы на этом останавливаться, тем более, что мы его применяем для предельно узкой задачи — заменить UDT объектным типом. |
▲ вверх
Методика тестирования
У нас подготовлено 9 VBA функций с именами: DA1S(), DA2S() и т.д., которые реализуют тестирование соответствующих структур. Под тестированием понимается полное заполнение структуры специально подготовленными данными. Данные одинаковы для всех алгоритмов. Далее осуществляется полный перебор структуры, но не последовательный, а по случайным ключам. Время измеряется и логируется. Процесс повторяется для всех алгоритмов с разным количеством элементов N уровня L1. Начинаем от N=1000, заканчиваем на N=70000.
▲ вверх
Описание структур
-
Структура DA1S
Реализация Описание На первом уровне используем Dictionary, на втором — одномерный массив с элементами типа String. И ключи второго уровня, и переменные третьего — всё упаковывается в текстовую строку с разделителями. Преимущества Один из лучших алгоритмов с точки зрения экономии памяти. Недостатки Недостатков хватает. Операции со строками (упаковка, распаковка, преобразование типов) занимают массу времени. Опять же для поиска на L2 приходится распаковывать в среднем 9 лишних строк, чтобы найти нужную. Это всё обуславливает чуть ли не самое худшее время работы. ▲ вверх
-
Структура DA2S
Реализация Описание Level 1 — Dictionary, Level 2 — двумерный массив M x 2 строковых элементов, Level 3 — упакованная строка с разделителями. Преимущества DA2S потребляет памяти не сильно больше, чем его младший брат — DA1S, однако, в сравнении с ним серьёзно, более чем в 2 раза, повысилась скорость, так как теперь поиск на втором уровне осуществляется при помощи двоичного поиска и ключ больше не хранится в упакованной строке. Надо сказать, что все массивы на уровнях L1 и L2 я сортирую (Sub QuickSort_D2_Variant), а затем использую процедуру двоичного поиска (Function BinaryMatchStringD2). Это спорно при небольших числах M (количество элементов на уровне 2, у нас тут сейчас 20), но при росте этого числа алгоритм будет на этом экономить драгоценное время. Спорно из-за того, что затраты времени на сортировку могут не окупиться при небольшом количестве элементов в массиве. Недостатки Ярковыраженных недостатков нет, однако, код выглядит достаточно громоздко. ▲ вверх
-
Структура DA2V
Реализация Описание Ещё одна ветка развития DA1S. В этой версии структуры мы избавились от упакованной строки. L1 — словарь, L2 — массив с размерами M x 4 элементов с типом Variant. Преимущества Данная структура незначительно быстрее DA1S. Каждая переменная — в своей коробочке. Недостатки Памяти структура потребляет значительно больше, чем DA1S, а вот прирост в производительности достигнут совсем незначительный. Это происходит из-за того, что тип Variant занимает много места в памяти и обрабатывается существенно медленнее. DA2V гораздо медленнее, чем DA2S. ▲ вверх
-
Структура CA2V
Реализация Описание На L1 у нас — коллекция, далее двумерный массив размерностью M x 4 элементов типа Variant. По-сути, это тоже самое, что и DA2V, но вместо словаря использована коллекция. Зная, что коллекция медленнее словаря, я не стал плодить множество вариантов структур, использующих коллекции, а добавил лишь эту, чтобы мы смогли наглядно убедиться в этом. Преимущества Преимуществ в сравнении с DA2V нет никаких. Недостатки Медленнее, чем тоже самое, но со словарём. Однако, медленнее на проценты (около 7%), а не в разы. В общем же зачёте скорость очень плохая — третья с конца. Код выглядит довольно громоздко. ▲ вверх
-
Структура A2A2V
Реализация Описание Это уже знакомый нам DA2V или CA2V, но вместо словаря/коллекции тут применён массив размерностью N x 2 с типом элементов Variant, так как в половине элементов этого массива должны храниться другие массивы. Преимущества Данная структура демонстрирует отменную производительность (третий результат), что порождает во мне сомнения (сравнивая с DA2V), а так ли уж эффективно ищет Dictionary, если двоичный поиск, реализованный на VBA мною, его с лёгкостью обходит? И есть ли там вообще двоичный поиск… и, не должен ли я самостоятельно позаботиться, чтобы элементы Dictionary были отсортированы, чтобы двоичный поиск заработал… Это вопросы для будущих исследований. Недостатки Код стал совсем нелаконичным. ▲ вверх
-
Структура A2A2A1V
Реализация Описание Довольно экзотическая реализация структуры. L1 — массив из N x 2 элементов типа Variant, L2 — массив из M x 2 элементов типа Variant, L3 — массив из 3-х элементов типа Variant. Преимущества Рекордсмен по экономии памяти. Недостатки В коде чёрт ногу сломит — многоэтажные ссылки (смотрите, например, строки кода 22-24). Хорошей скоростью похвастаться не может — середнячок. ▲ вверх
-
Структура A1UU
Реализация Описание Интересная структура. Построена на пользовательском типе (UDT), да не простом, а вложенном, то есть один UDT, является составной частью другого. На первом уровне одномерный массив из N элементов с типом externalUDT. Вот как описывается этот тип: Преимущества A1UU демонстрирует отличную производительность при малом количестве элементов N. И я думаю, что будь реализована для UDT сортировка и линейный поиск, то это могло бы быть чёткое третье место, а то и повыше. Недостатки До 5000 элементов на L1 она стабильно демонстрирует третий результат скорости, но с ростом элементов скорость стремительно деградирует и к 70000 эта структура подходит с худшим результатом и до ближайшего соседа по несчастью — разрыв в три сотни процентов. Это безусловно связано с тем, что я для столь сложной структуры не реализовал линейный поиск, так как имеющиеся функции надо было бы переписывать чуть менее, чем полностью. Поэтому, кстати, и код выглядит ужасно. ▲ вверх
-
Структура DDA1V
Реализация Описание Это наш фаворит. Первые два уровня — словари. То есть словарь первого уровня в качестве своих items имеет объекты словарей второго уровня. И всего создаётся N+1 объектов типа Dictionary. Преимущества Лучший результат по скорости! За счёт подпрограмм InsertedDic_Add и InsertedDic_Get код выглядит чисто, лаконично и опрятно. Ничего лишнего. Ошибиться крайне сложно при написании кода. Первое место. Недостатки Худший результат по памяти. Тут, правда, стоит сказать, что я не знаю, сколько объект типа Dictionary занимает в памяти. Ясно, что методы объекта (код) существуют в памяти скорее всего в одном экземпляре, а вот данные (в том числе private) конечно же существуют в количестве N+1. Но конкретные цифры мне найти не удалось. ▲ вверх
-
Структура DDC
Реализация Описание То же, что и DDA1V, но вместо одномерного массива используется класс. Класс нужен для того, чтобы отказаться от этого массива и перейти на нечто схожее с UDT, но так как UDT не может быть в качестве полезной нагрузки для item-ов словаря, то приходится городить класс. Впрочем это совершенно не сложно. Преимущества Код выглядит даже лучше, чем у DDA1V. Памяти, скорее всего, тратит столько же (может чуть выше из-за дополнительного пустого класса).
Скорость чуть-чуть уступает DDA1V — второе место с разрывом оносительно победителя порядка 3%.Недостатки Только память, а это, учитывая нынешние стандартные конфигурации компьютеров, не такая уж и большая проблема.
▲ вверх
Сравнительный анализ
Время, которое показали все структуры в процессе тестирования. Зелёное — лучше, красное — хуже. По скорости работы выявлены 2 практически равноценных победителя: DDA1V и DDC. Как уже было сказано, структура A1UU демонстрирует отличные результаты на малых числах N и имеет отличные шансыулучшить свои характеристики после разработки процедур сортировки массивов, работающих с UDT типами.
График «скорость — число элементов» на L1
Тот же график, но вблизи малого числа элементов (до 20000)
Индикаторы по всем структурам, плюс относительное время и расход памяти.
▲ вверх
Файл проекта
Скачать
▲ вверх
Итоговые рекомендации
-
При росте количества элементов в структурах необходимо либо использовать объект Dictionary, либо массивы совместно с подпрограммами быстрой сортировки и бинарного поиска. Примеры таких подпрограмм вы можете найти в файле примера в модуле QSORT
-
Структура, построенная на вложенных друг в друга Dictionary очень эффективна с точки зрения быстродействия. К тому же эта структура сильно расширяет ваши возможности по организации сложных структур данных и, будучи снабжённой подпрограммами по работе с ней, упрощает программирование таких структур.
-
Также перспективным направлением является использование массивов с элементами в виде пользовательского типа (UDT), но необходимо написать для неё процедуры сортировки и бинарного поиска.
-
Если вы пользуетесь объектами типа Collections, то смело переходите на Dictionary. Рекомендую использовать позднее связывание при создании объектов Dictionary (кстати в моём примере сделано как раз наоборот, поэтому, если у вас не заработали словари, то включите в Tool — References ссылку на Microsoft Scripting Runtime, так как словарь является частью VBScript библиотеки.
-
Помните, что победители данного обзора потребляют много оперативной памяти, поэтому хотя бы на пальцах прикидывайте в какие размеры это всё выливается. В файле проекта на листе MemUsage даны мои прикидки.
▲ вверх
Читайте также:
-
Работа с объектом Range
-
Поиск границ текущей области
-
Массивы в VBA
-
Автоматическое скрытие/показ столбцов и строк
Let’s say you are trying to create a school management system. Here, you will have different types of variables like student name, student roll no, class, etc. A school also has teachers, so there will be teacher names, teacher subject, classes, etc. Similarly, there will be many other objects like, librarian, classes, principle etc. Now having different variables for each entity in school will be messy work. How about creating a data type of student, teacher, classes, etc that stores values related to them. For this we can use defined data types of VBA.
In this article, we will learn how you can create your own data type in VBA. They are referred to as UDTs of VBA.
Defining a User Defined Data Type
To define a structure or UDTs in VBA we use Type___End Type block. Here’s the syntax of a UDT.
Type Tname_Of_Data_Type var1 as datatype 'datatype can be anything, int, array,or even UDT var2 as datatype Var3() as datatype --- VarN() as datatype End Type
So to define a custom data type in VBA we start with Type Keyword. Then we write the name of our custom data type. It is convention to use T before the Name of Data Type so that you can differentiate between vba collections and UDTs.
The DataTypes can be anything. And Integer, String, Variant, another UDT, Arrays, collections, anything.
To use your UDT in the program declare its variable like any other variable.
Sub UseUDT 'Declaring variable of user defined data type Dim myVar1 as Tname_Of_Data_Type Dim myVar2 as Tname_Of_Data_Type End Sub
Simple. Now to use the variables within this UDT we use dot operator. Use the name of the data type followed by a dot and name of variable within.
Sub UseUDT 'Declaring variable of user defined data type Dim myVar1 as Tname_Of_Data_Type Dim myVar2 as Tname_Of_Data_Type myVar1.var1="Abcd" myVar2.Var2="xyvz" End Sub
Enough of the theory, let’s jump into an example to see how it works.
Create A Student Variable that Stores Information Related to Student
So we have a task to create a user defined data type that stores information related to students.
A student has a first name, last name, roll number, date of birth, class, section, subjects.
So let’s create it.
'Created a Public Student Data Type Public Type Tstudent fName As String 'For First Name lName As String 'For Last Name rNo As Integer 'For Roll Number clss As string 'For Class section As String 'For Section Name subjects() As String 'For Subjects of student End Type 'Use this Tstudent type in subroutine Sub StudentsInfo() 'Creating and initializing student type variable Dim student1 As Tstudent student1.fName = "Manish" student1.lName = "Singh" student1.rNo = 12334 student1.clss = 10 student1.section = "A" ReDim student1.subjects(2) student1.subjects(0) = "physics" student1.subjects(1) = "Math" 'Printing student details. Debug.Print (student1.fName) Debug.Print (student1.lName) Debug.Print (student1.rNo) Debug.Print (student1.clss) Debug.Print (student1.section) Debug.Print (student1.subjects(0)) Debug.Print (student1.subjects(1)) End Sub
When you run the above sub it will print the result as shown below:
Singh
12334
10
A
physics
Math
Creating an Array of UDTs and Accessing Elements
Similarly you can create as many as variables of Tstudent type you need. You can even create an array of Tstudent type like any other data type.
Public Type Tstudent fName As String 'For First Name lName As String 'For Last Name rNo As Integer 'For Roll Number clss As string 'For Class section As String 'For Section Name subjects() As String 'For Subjects of student End Type 'Creating an arrays of Tstudents type Sub SchoolInfo() Dim schoolName As String Dim students() As Tstudent schoolName = "Senior School" ReDim students(10) For i = 0 To 9 students(i).fName = "name" & Str(i + 1) students(i).rNo = i + 1 Next i Debug.Print ("Name : Roll No") For i = 0 To 9 Debug.Print (students(i).fName & " : " & students(i).rNo) Next i End Sub
When you run this code, this will be printed in the immediate window.
name 1 : 1
name 2 : 2
name 3 : 3
name 4 : 4
name 5 : 5
name 6 : 6
name 7 : 7
name 8 : 8
name 9 : 9
name 10 : 10
In the above code, first defined UDT structure before and the sub (I’ll explain later why). The we just created an array using a dim keyword like we do for any variable in VBA.
Then we used Redim to define the size of arrays. Afterwards we use a for loop to initialize the array.
To access the structure’s elements we use another for loop. That is it.
Why Did We Declare UDT on Top of the Module?
If we declare a UDT first in a module, outside of any subroutine or function, it is available to all the modules in the workbook. It means if you have a hundred subs and functions in a module all of them can declare Student type variables in their body.
If the UDT is not private, it will be available to all the modules in the workbook. If want a structure (UDT) to be available only to a containing module, declare it private.
Private Type Tstudent fName As String lName As String rNo As Integer clss As Integer section As String subjects() As String End Type
You can’t have UDT on a procedural level. It means you can’t define a user defined data type inside a subroutine or function.
Nested User Defined Types
Let’s say you have UDT called a car. Car has its own elements. Similarly you have a UDT called a bike that can have its own properties.
Now let’s say you need a data type called vehicle. Vehicle can have a car and bike as its elements. Can we do this? Yes we can do this. See the below code
Private Type Tcar seats As Integer ac As Boolean typ As String color As String manufacturer As String Dop As Date rc_no As String End Type Private Type Tbike seats As Integer typ As String color As String manufacturer As String Dop As Date rc_no As String End Type Private Type Tvehicle number_of_Vehicle As Integer bike As Tbike car As Tcar End Type Sub vehicleVarification() Dim myVehicles As Tvehicle myVehicles.number_of_Vehicle = 2 myVehicles.bike.seats = 1 myVehicles.bike.typ = "Racing" myVehicles.car.seats = "4" myVehicles.car.ac = True Debug.Print myVehicles.number_of_Vehicle Debug.Print myVehicles.bike.typ Debug.Print myVehicles.car.ac End Sub
Here, we have defined three user defined data type. First is Tcar that contains some information related to cars. Second is bike, it also contains some information about bike.
The third UDT is Tvehicle. It contains one variable to store number of vehicles and two variables of Tcar and Tbike type.
Private Type Tvehicle
number_of_Vehicle As Integer
bike As Tbike
car As Tcar
End Type
To access variables of Tcar and Tbike we can use Tvehicle data type. In the sub, we have defined only one variable of Tvehicle type as myVehicles. When we create this variable VBA creates variables of Tcar and Tbike too.
To initialize and access variables of Tcar and Tcar, we can use myVehicle variable. As you can see in the code.
myVehicles.number_of_Vehicle = 2
myVehicles.bike.seats = 1
myVehicles.bike.typ = «Racing»
myVehicles.car.seats = «4»
myVehicles.car.ac = True
When we run the sub, this how result occurs.
This feature really increases the power of programming VBA exponentially. You can structure your data type like real world entities. You can create relationships between data types which can be useful in a big project.
So yeah guys, this is how you can create and use a user defined data type or structure in VBA. I hope I was able to explain it. If you have any questions regarding this article or any other VBA related questions, ask me in the comments section below. I’ll be really happy to hear from you.
Related Articles:
VBA variables in Excel| VBA stands for Visual Basic for Applications. It is a programming language from Microsoft. It is used with Microsoft Office applications such as MSExcel, MS-Word and MS-Access whereas VBA variables are specific keywords.
Excel VBA Variable Scope| In all the programming languages, we have variable access specifiers that define from where a defined variable can be accessed. Excel VBA is no Exception. VBA too has scope specifiers.
ByRef and ByVal Arguments | When an argument is passed as a ByRef argument to a different sub or function, the reference of the actual variable is sent. Any changes made into the copy of the variable, will reflect in the original argument.
Delete sheets without confirmation prompts using VBA in Microsoft Excel | Since you are deleting sheets using VBA, you know what you are doing. You would like to tell Excel not to show this warning and delete the damn sheet.
Add And Save New Workbook Using VBA In Microsoft Excel 2016| In this code, we first created a reference to a workbook object. And then we initialized it with a new workbook object. The benefit of this approach is that you can do operations on this new workbook easily. Like saving, closing, deleting, etc
Display A Message On The Excel VBA Status Bar| The status bar in excel can be used as a code monitor. When your VBA code is lengthy and you do several tasks using VBA, you often disable the screen update so that you don’t see that screen flickering.
Turn Off Warning Messages Using VBA In Microsoft Excel 2016| This code not only disables VBA alerts but also increases the time efficiency of the code. Let’s see how.
Popular Articles:
50 Excel Shortcuts to Increase Your Productivity | Get faster at your task. These 50 shortcuts will make you work even faster on Excel.
The VLOOKUP Function in Excel | This is one of the most used and popular functions of excel that is used to lookup value from different ranges and sheets.
COUNTIF in Excel 2016 | Count values with conditions using this amazing function. You don’t need to filter your data to count specific values. Countif function is essential to prepare your dashboard.
How to Use SUMIF Function in Excel | This is another dashboard essential function. This helps you sum up values on specific conditions.
Создание пользовательских типов данных в VBA Excel. Оператор Type, его описание и параметры. Создание массива «одномерных массивов» с пользовательскими данными.
Определение пользовательских типов данных
Пользовательский тип данных в VBA Excel представляет из себя набор элементов, каждому из которых пользователем присваивается свой тип данных. Другими словами, пользовательский тип данных — это набор данных разного типа, который может быть присвоен одной переменной.
Если простую переменную (не массив) объявить с пользовательским типом данных, она будет представлять из себя «одномерный массив»* с элементами разных типов данных, определенных пользователем.
Если с пользовательским типом данных объявить переменную массива, она будет представлять из себя массив «одномерных массивов»* пользовательских данных.
* Выражение «одномерный массив» взято в кавычки, так как фактически это не массив, а набор пользовательских данных, но для практического применения это не имеет значения.
Синтаксис оператора Type
Type <strong>Name</strong> <strong>Element</strong>_1 as <strong>Tip</strong> <strong>Element</strong>_2 as <strong>Tip</strong> <strong>Element</strong>_3 as <strong>Tip</strong> ———————— <strong>Element</strong>_n as <strong>Tip</strong> End Type |
Пользовательский тип данных в VBA Excel может быть объявлен с ключевым словом Public или Private, которое явно укажет зону его видимости. Если ключевое слово опущено, конструкция с оператором Type по умолчанию объявляется с зоной видимости Public.
Параметры оператора Type
Параметр | Описание |
---|---|
Name | Имя пользовательского типа данных, по которому этот тип данных будет присваиваться переменным. |
Element | Наименование отдельного элемента пользовательского типа данных. |
Tip | Тип данных отдельного элемента (стандартный тип VBA). |
Применение пользовательских типов данных
Применение пользовательских типов данных в VBA Excel рассмотрим на примере домиков для животных.
Объявление пользовательского типа данных
Объявление пользовательского типа данных (конструкция с оператором Type) размещается в самом начале модуля в разделе Declarations.
Пример 1
Type Domik naimenovaniye As String obyem_m3 As Single material As String kolichestvo As Long End Type |
В этом примере:
- Domik — имя, по которому этот тип данных будет присваиваться переменным;
- naimenovaniye — наименование домика для животных;
- obyem_m3 — объем домика в куб. метрах;
- material — материал, из которого сделан домик;
- kolichestvo — количество домиков на складе.
Заполнение данными массива
Обычно в качестве контейнеров для пользовательских типов данных в VBA Excel используются массивы. В простую переменную можно уместить только один набор пользовательских данных, а в массив — сколько нужно. В следующем примере мы заполним трехэлементный массив тремя наборами пользовательских данных.
Если представить набор пользовательских данных как «одномерный массив», то таким образом мы создадим массив «одномерных массивов» с пользовательскими данными.
Пример 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Sub Primer2() ‘Объявляем трехэлементный массив ‘с пользовательским типом данных Dim a(1 To 3) As Domik ‘Заполняем первый элемент массива a(1).naimenovaniye = «Скворечник» a(1).obyem_m3 = 0.02 a(1).material = «сосна» a(1).kolichestvo = 15 ‘Заполняем второй элемент массива a(2).naimenovaniye = «Собачья будка» a(2).obyem_m3 = 0.8 a(2).material = «береза» a(2).kolichestvo = 5 ‘Заполняем третий элемент массива a(3).naimenovaniye = «Клетка кролика» a(3).obyem_m3 = 0.4 a(3).material = «металл» a(3).kolichestvo = 6 End Sub |
Обращение к пользовательским данным в массиве
Для обращения в коде VBA Excel к пользовательским данным в массиве используется та же конструкция, что и при записи: указывается элемент массива и через точку наименование элемента пользовательских данных.
Пример 3
‘Считываем информацию из массива Dim b As Variant b = a(2).naimenovaniye MsgBox b b = a(3).obyem_m3 MsgBox b b = «Мы продаем следующие товары: « _ & a(1).naimenovaniye & «, « _ & a(2).naimenovaniye & » и « _ & a(3).naimenovaniye MsgBox b |
Для наглядной демонстрации вставьте строки кода Примера 3 перед строкой End Sub Примера 2.
val = col(«Key1»)
val = col(2)
Определяемые пользователем типы данных
Язык VBA предоставляет программисту достаточно большие возможности для создания и использования специфических типов данных: структур и перечислений.
Структуры
Структура – это сложный тип данных, представляющий собой совокупность переменных, хранящихся и обрабатываемых совместно. Переменные, входящие в состав структуры, называются полями (членами) структуры. В состав структуры могут входить переменные как стандартных, так и определенных пользователем типов данных.
Использование структур в программах зачастую позволяет уменьшить объем и сложность алгоритмов работы с данными. Например, для хранения большого количества записей с именами, адресами и телефонами потребовались бы три массива. При использовании же структуры с полями для имени, адреса и телефона для хранения всей информации потребуется всего один массив (VBA позволяет создавать массивы структур).
Описание структур
Для описания структуры в программе на VBA в блок деклараций модуля необходимо поместить следующую конструкцию:
[Public | Private] Type Имя_структуры
Поле1
Поле2
…
ПолеN
End Type
Ключевые слова Public и Private задают область видимости структуры (по умолчанию используется Public):
• Publiс – применяется для описания структуры, которую можно использовать (объявлять переменные этого типа) во всех модулях проекта; недопустимо в модулях класса;
• Private – применяется для описания структуры, которую можно использовать только в том модуле, где эта структура описана.
После ключевого слова Туре следует имя описываемой структуры. Внутри блока Type-End Туре помещаются объявления переменных-членов структуры. Эти объявления аналогичны объявлениям обычных переменных и отличаются только отсутствием в начале ключевых слов Dim, Static, Private или Public и тем, что в одной строке можно объявлять только одну переменную.
Пусть некоторой компании необходимо хранить данные об имени, фамилии, адресе, телефоне и дате рождения своих сотрудников. Совместно с этими данными нужно хранить информацию о проекте, в котором принимает участие каждый сотрудник. Ниже представлено описание структур, с помощью которых можно реализовать хранение требуемых данных.
Type ПроектИнформация
Название As String
Срок_завершения As Date
End Type
Type Сотрудник
Имя As String
Фамилия As String
Адрес As String
Телефон As String
Дата_рождения As Date
Проект As ПроектИнформация
End Type
Далее на этом примере рассмотрим особенности работы со структурами в программах на VBA.
Объявление переменных, содержащих структуры
Объявления переменных, содержащих структуры, выглядят точно так же, как объявления переменных другого типа. Ниже приведен пример объявления одной переменной, содержащей структуру Сотрудник:
Dim worker As Сотрудник
VBA позволяет создавать массивы любых типов данных, в том числе и структур:
Dim workers (15) As Сотрудник
В данном случае будет создан массив из 15 структур типа Сотрудник.
Примечание
При объявлении переменных, содержащих структуры, происходит автоматическая инициализация всех полей созданных структур.
Доступ к полям структур
Для доступа к содержимому полей структуры необходимо использовать символ «.» (точка). Ниже приведен пример получения значений полей с именем и телефоном сотрудника:
strFirstName = worker.Имя
strPhone = worker.Телефон
При доступе к массиву структур получение значений полей будет выглядеть следующим образом:
strFirstName = workers(15). Имя
strPhone = workers(15). Телефон
Получить значения полей вложенной структуры можно следующим образом (Проект – вложенная структура):
strName = worker.Проект. Название
datDate = worker.Проект. Срок_завершения
При работе со структурами необходимо помнить, что каждое поле структуры – это переменная, которой можно присваивать значение. Ниже приведен пример заполнения структуры с информацией о сотруднике:
worker.Имя = «Иван»
worker.Фамилия = «Иванов»
worker.Адрес = «ул. Первомайская, д. 100, кв. 5»
worker.Телефон = «(095) 200 00 00»
worker.Дата_рождения = «12.03.1978»
worker.Проект. Название = «План здания»
worker.Проект. Срок_завершения = «15.09.2005»
Содержимое полей структур можно использовать в любых корректных выражениях, например:
strFullName = «Имя: » & worker.Имя & «, фамилия: » & worker.Фамилия
При использовании заполненной чуть выше структуры (с информацией о сотруднике Иванове) строка strFullName в результате обработки выражения получит значение» Имя: Иван, фамилия: Иванов».
Перечисления
VBA позволяет определять целочисленные типы данных с ограниченным количеством значений – перечисления. Каждому значению перечисления соответствует идентификатор.
Использование перечислений, во-первых, позволяет оградить программиста от ошибок (не нужно знать значения элементов перечислений), а во-вторых, может повысить читаемость программного кода, так как вместо малоинформативных значений типа 167353b программе используются идентификаторы типа Actions ave. Использование перечислений также избавляет от необходимости создания глобальных целочисленных констант, которые используются только как значения параметров функций и процедур.
Описание перечислений
Для описания перечисления в блок деклараций модуля необходимо поместить следующую конструкцию:
[Public | Private] Enum Имя_перечисления
Идентификатор1 [= Значение1]
Идентификатор2 [= Значение2]
…
Идентификатор1 [= ЗначениеN]
End Enum
Ключевые слова Public и Private задают область видимости перечисления точно так же, как для структуры (см. выше).
После ключевого слова Enum следует имя описываемого перечисления. Внутри блока Enum—End Enum задаются идентификаторы значений перечисления и, если нужно, сами значения, которые сопоставляются с идентификаторами.
Если значение элемента перечисления явно не указывается, то оно автоматически формируется следующим образом:
• если элемент перечисления первый, то тогда ему присваивается нулевое значение;
• если элемент не первый, то его значение равняется значению предыдущего элемента, увеличенному на единицу.
Ниже приведен пример описания перечисления:
Enum MyEnum
value1
value2 = 100
value3
End Enum
В приведенном примере создается перечисление, содержащее три идентификатора и значения. При этом с идентификаторами значения сопоставлены следующим образом: value1 имеет значение 0, value2 – значение 100, a value3 – 101.
Использование перечислений
Объявление переменных для перечислений ничем не отличается от объявления переменных других типов. Ниже приведены примеры объявления переменной и массива переменных для перечисления MyEnum:
Dim EnumValue As MyEnum
Dim EnumValues(255) As MyEnum
Таким переменным можно присваивать любые численные значения, но можно (и даже нужно) использовать идентификаторы этих значений. Например:
EnumValue = value1
EnumValues(100) = value3
Идентификаторы значений элементов перечисления можно использовать во всех выражениях, в которых употребляются переменные с типом соответствующего перечисления. Например:
If EnumValue = value2 Then…
Здесь значением выражения EnumValue = value2 является True, если EnumValue имеет значение value2 (или 100), и False – в противном случае.
Управление выполнением программы
Язык VBA поддерживает ряд способов управления порядком выполнения инструкций программы в пределах функции или процедуры: инструкции безусловного и условного перехода, циклы. Большое количество этих инструкций и наличие различных вариантов обеспечивают максимально эффективное и удобное их использование при написании программ.
Циклы
В VBA реализовано несколько способов организации циклов. Их разнообразие и гибкость играют существенную роль в упрощении программ на языке VBA, а также во многом способствуют повышению наглядности программного кода.
VBA поддерживает четыре вида циклов: обычный цикл For-Next, цикл For Each-Next для просмотра элементов массивов и коллекций, циклы While-Wend и Do-Loop. Циклы различных видов могут быть вложены друг в друга. Рассмотрим подробно каждый из приведенных циклов.
Цикл For-Next
Цикл For-Next в VBA является самым простым и очень часто используемым. Формат данного цикла следующий:
For Счетчик = Начальное_значение To Конечное_значение [Step Шаг]
[Инструкции]
[Exit For]
[Инструкции]
Next [Счетчик]
Здесь Счетчик – это переменная-итератор любого численного типа. Началъное_значение, Конечное_значение, Шаг – численные значения или идентификаторы переменных численного типа. После ключевого слова Next можно (но не обязательно) указывать идентификатор итератора цикла, конец тела которого обозначает данное ключевое слово. Указывать идентификатор переменной-итератора после Next особенно удобно при организации сложных вложенных циклов.
В начале выполнения цикла итератору присваивается значение элемента Начальное_значение. Инструкции, записанные в теле цикла, выполняются до тех пор, пока значение итератора не превзойдет значение элемента Конечное_значение (станет больше или меньше его в зависимости от направления изменения итератора). Шаг и направление изменения итератора (увеличение или уменьшение) задаются элементом Шаг. Если шаг изменения итератора равен единице, то данный элемент можно опустить.
Для преждевременного выхода из цикла предусмотрена инструкция Exit For. При ее встрече в теле цикла выполнение программы переходит на следующую инструкцию после ключевого слова Next.
Ниже приведен пример трех вложенных циклов For-Next, итераторами которых являются целочисленные переменные i, j и к:
For i = 10 To 1 Step -1
For j = 1 To 20
For k = 10 To -10 Step -2
‘ Выполнение каких-то действий
…
Next k
Next j
Next i
Цикл For Each-Next
Цикл For Each-Next используется для просмотра всех элементов массива или коллекции. Формат данного цикла следующий:
For Each Элемент In Контейнер
[Инструкции]
[Exit For]
[Инструкции]
Next [Элемент]
Здесь Элемент – это идентификатор переменной-итератора, а Контейнер – идентификатор массива или коллекции. Для цикла For Each-Next допустимый тип итератора зависит от того, просматривается массив или коллекция. При просмотре массива итератор должен иметь тип Variant. При просмотре коллекции итератор может иметь тип Variant или быть ссылкой на объект.
После ключевого слова Next можно (но не обязательно) указывать идентификатор итератора цикла, конец тела которого обозначает данное ключевое слово.
Чтобы преждевременно выйти из цикла, можно использовать такую же инструкцию Exit For, как и для цикла For-Next.
Ниже приведен пример использования цикла For Each-Next для просмотра массива astrStrings:
For Each varItem In astrStrings
‘ Выполнение каких-то действий над элементом varItem
…
Next
Цикл While-Wend
While-Wend являeтcя самым простым циклом, с помощью которого можно осуществлять определенные действия до тех пор, пока выполняется заданное условие. Формат данного цикла следующий:
While Условие
[Инструкции]
Wend
Инструкции в теле цикла While-Wend выполняются до тех пор, пока логическое выражение Условие имеет значение True (значение этого выражения вычисляется при каждой итерации).
Ниже приведен пример организации цикла While-Wend:
While i < 100
‘ Действия в цикле
…
i = i + 3
Wend
Следует отметить, что цикл While-Wend является значительно упрощенным и ограниченным с точки зрения разнообразности способов его использования.
Цикл Do-Loop
Цикл Do-Loop предоставляет гораздо больше возможностей при организации циклических действий с проверкой логического условия, чем цикл While-Wend. Проверка логического условия окончания цикла может происходить в начале каждой итерации цикла, при этом формат цикла следующий:
Do [While | Until Условие]
[Инструкции]
[Exit Do]
[Инструкции]
Loop
Проверка условия может также происходить в конце каждой итерации цикла (тогда выполняется как минимум одна итерация цикла):
Do
[Инструкции]
[Exit Do]
[Инструкции]
Loop [While | Until Условие]
В приведенных форматах Условие – любое логическое выражение. При использовании ключевого слова While цикл выполняется до тех пор, пока Условие имеет значение True, а при использовании ключевого слова Until – пока Условие имеет значение False. Для выхода из цикла предусмотрена инструкция Exit Do.
Ниже приведен пример использования цикла Do-Loop:
Do While i < 100
i = i + 1
Do
j = j + 5
‘ Действия
…
Loop Until j > 200
Loop
Инструкции выбора
Язык VBA поддерживает инструкции, позволяющие осуществлять различные действия в зависимости от выполнения или невыполнения заданных условий, – инструкции выбора If-Then-Else и Select.
Инструкция If-Then-Else
Инструкция VBA If-Then-Else предоставляет возможность выбора одного из действий в зависимости от значений заданных логических выражений. Формат данной инструкции следующий:
If Выражение1 Then
[Инструкции1]
[ElseIf Выражение2 Then
[Инструкции2]]
…
[ElseIf ВыражениеN Then
[ИнструкцииN]]
[Else
[Инструкции]]
End If
Здесь Выражение1 – ВыражениеN – логические выражения. Если какое-либо из них истинно, то выполняются инструкции, находящиеся после соответствующего ключевого слова If или Elself. Если ни одно из выражений не является истинным, то выполняются инструкции, записанные после ключевого слова Else (если, конечно, это ключевое слово используется).
Рассмотрим пример использования инструкции If-Then-Else:
If intAction = 1 Then
‘ Выполнение сложения
res = a + b
ElseIf intAction = 2 Then
‘ Выполнение вычитания
res = a – b
ElseIf intAction = 3 Then
‘ Выполнение умножения
res = a * b
Else
‘ Заданное действие не поддерживается
‘…
End If
В приведенном примере с помощью инструкции If-Then-Else выбирается одно из трех поддерживаемых действий для переменных а и Ь: сложение, вычитание или умножение. Действие, которое необходимо выполнять, определяется по содержимому переменной intAction. Если она имеет значение, отличное от 1, 2 и 3, то выполняются инструкции, следующие непосредственно после ключевого слова Else.
Язык программирования VBA также поддерживает упрощенный вариант инструкции If-Then-Else:
If Выражение Then [Инструкции1] [Else Инструкции2]
Здесь Выражение – это логическое выражение, при истинном значении которого выполняются инструкции после ключевого слова Then. Если Выражение не истинно, то выполняются инструкции после ключевого слова Else (если это ключевое слово используется). При использовании этой формы инструкции If-Then-Else следует учитывать, что она записывается в одну строку (или в несколько строк, но с использованием символа подчеркивания). Также необходимо учитывать, что Инструкции и Инструкции1 представляют собой либо одну инструкцию VBA, либо несколько инструкций, разделенных двоеточием.
Если ключевое слово Else используется, то элемент Инструкции1 может отсутствовать.
Ниже приведены несколько примеров использования сокращенного варианта инструкции If-Then-Else:
If a = 1 Then a = 2 Else a = 1
If a = 1 Then a = 2 Else a = 1: b = b + 1
If a = 1 And b = 0 Then Else a = 1: b = b + 1
Инструкция Select Case
Select Case позволяет, подобно инструкции If-Then-Else, делать выбор выполняемых программой действий в зависимости от значения заданного аргумента. При большом количестве альтернатив данная инструкция работает быстрее инструкции If-Then-Else, так как значение проверяемого выражения вычисляется только один раз. Формат инструкции Select Case приведен ниже:
Select Case Проверяемое_выражение
[Case Список_выражений
[Инструкции]]…
[Case Else
[Инструкции]]
End Select
Здесь Проверяемое_выражение – это любое численное или строковое выражение. Список_выражений содержит неограниченное количество выражений, диапазонов значений и условий. Для более детального пояснения ниже приведен формат элемента Список_выражений:
Выражение | Мин_значение To Макс_значение | Is Оператор Выражение _
[, Выражение | Мин_значение To Макс_значение | Is Оператор Выражение]…
Значения элементов приведенной конструкции следующие.
Выражение – это любое численное или строковое выражение (тип элемента Выражение должен соответствовать типу элемента Проверяемое_выражение).
Мин_значение То Макс_значение – используется для задания диапазона значений. Элементы Мин_значение и Макс_значение задают минимальное и максимальное значения диапазона соответственно.
• Is Оператор Выражение – используется для задания условий. Позволяет использовать в инструкции Select Case операторы сравнения. Элемент Оператор – это любой оператор сравнения VBA, кроме Is и Like. Элемент Выражение – это любое выражение, тип которого соответствует типу элемента Проверяемое_выражение.
При соответствии значения элемента Проверяемое_выражение одному из заданных выражений, при попадании значения этого элемента в один из диапазонов или при выполнении одного из заданных условий происходит выполнение инструкций, записанных после соответствующего ключевого слова Case. Если ни одна Case-конструкция не сработала, то выполняются инструкции после сочетания ключевых слов Case Else.
Допустим, что в программе необходимо проверять значение численной переменной intTestValue и выполнять одни действия, когда эта переменная имеет значение 1, 2, 3 или 5, и другие действия – в противном случае. Приведенный ниже фрагмент программы позволяет решить поставленную задачу:
Select Case intTestValue
Case 1 To 3, 5
‘ Действия при значении переменной intTestValue,_
равном 1, 2, 3 или 5
Case Is < 1, Is > 3
‘ Действия при значении переменной intTestValue _
меньше 1 или больше 3
End Select
В данном примере необходимо обратить внимание на то, что значение 5 удовлетворяет обеим Case-конструкциям. При обработке инструкции Select Case VBA просматривает конструкции с ключевым словом Case в том порядке, в котором они следуют в программе. Поэтому в приведенном примере при значении переменной intTestValue, равном 5, выполняются инструкции после первого ключевого слова Case.
Не менее просто с помощью инструкции Select Case можно обрабатывать и строковые значения. Ниже приведен пример, в котором выполняются различные действия при значениях строковой переменной strTestValue, начинающихся со строчной и прописной букв латинского алфавита:
Select Case strTestValue
Case «a» To «z»
» Действия, если строка strTestValue начинается _
со строчной буквы латинского алфавита
Case «A» To «Z»
» Действия, если строка strTestValue начинается _
с прописной буквы латинского алфавита
Case Else
» Действия, если строка не начинается с символа _
латинского алфавита
End Select
Инструкции безусловного перехода
С помощью инструкций безусловного перехода можно приступать к выполнению части заданной программы без проверки каких-либо условий. К таким инструкциям относятся GoTo и пара GoSub-Return. Однако перед их рассмотрением необходимо ознакомиться еще с одним элементом языка VBA, без которого данные инструкции использоваться не могут, – с метками.
Метки
Метка – это идентификатор VBA или целое число, которое располагается в начале строки и заканчивается двоеточием. Метки используются для указания строк, на которые можно переходить с помощью инструкций GoTo и GoSub. Примеры меток приведены ниже:
100:
DoSomeAction:
Перерасчет:
После перехода на метку выполняются все инструкции, расположенные после нее до конца процедуры, функции, следующих инструкций GoTo, GoSub или до инструкции Return (см. далее).
Инструкция GoTo
Инструкция GoTo используется для простого перехода к выполнению программы после нужной метки. Формат инструкции следующий:
GoTo Имя_метки
Инструкции, расположенные после GoTo, выполняются только в том случае, если в программе существуют соответствующие инструкции GoTo или GoSub. Рассмотрим пример использования GoTo:
a = 15 + b
If a < 0 Then GoTo 10
‘ Выполнение действий для значения переменной a больше нуля
10:
‘ Выполнение действий для значения переменной a меньше нуля
Следует отметить, что частое использование инструкции GoTo в программе не рекомендуется, так как может сделать алгоритм слишком запутанным. GoTo нередко допустимо заменить инструкциями выбора либо вызовом процедуры или функции.
Пара инструкций GoSub-Return
Во времена старого доброго языка Basic инструкции GoSub и Return были незаменимы для программиста. Это было связано с тем, что Basic не был даже процедурным языком программирования: в нем не было процедур и функций, все инструкции записывались в виде единой программы. Чтобы не реализовывать несколько раз одинаковые действия, в этой большой программе выделялись отрезки кода, выполняющие типичные действия, – подпрограммы. Подпрограмма начиналась некоторой меткой и оканчивалась инструкцией Return.
При достижении инструкции Go Sub осуществлялся переход на указанную метку (аналогично инструкции GoTo) – начинала выполняться подпрограмма. При достижении инструкции Return происходил возврат из подпрограммы – выполнение программы продолжалось после последней инструкции Go Sub.
Пара инструкций GoSub-Return в языке VBA работает точно таким же образом, но переходы осуществляются только в пределах процедуры или функции. Формат инструкций GoSub-Return такой:
GoSub Имя_метки
[Инструкции]
Имя_метки:
[Инструкции подпрограммы]
Return
Ниже приведен пример использования инструкций GoSub-Return (в подпрограмме вычисляется квадрат длины гипотенузы прямоугольного треугольника):
a = 5
b = 4
GoSub Calculate
‘ Другие действия
…
Calculate:
‘ Подпрограмма
c2 = a ^ 2 + b ^ 2
Return
Следует отметить, что при процедурном, а тем более объектно-ориентированном программировании необходимость использования подпрограмм полностью отпала. Роль подпрограмм выполняют функции и процедуры.
Процедуры и функции
В языке VBA программист должен записывать все инструкции своей программы внутри специальных блоков: функций и процедур. Код внутри процедуры или функции представляет собой подпрограмму, выполняющую требуемые действия. Перед рассмотрением способов создания процедур и функций необходимо узнать, чем же различаются эти два вида подпрограмм в VBA.
Процедура – это подпрограмма, которая выполняет действия, не возвращая никакого значения в качестве результата либо возвращая некоторые значения путем изменения переданных ей параметров. Функция в дополнение к возможностям процедуры может возвращать некоторое результирующее значение.
Далее в этом разделе будут рассмотрены особенности создания и использования процедур и функций в программах на VBA.
Объявление процедур
Для объявления процедуры в VBA используется следующая конструкция:
[Private | Public] [Static] Sub Имя_процедуры [(Список_аргументов)]
[Инструкции]
[Exit Sub]
[Инструкции]
End Sub
Ключевые слова Private и Public данной конструкции задают область видимости процедуры.
• Public – применяется по умолчанию, позволяет создать процедуру, которую можно вызывать из любого места проекта VBA. При использовании в модуле класса она дает возможность создавать общую процедуру (метод) этого класса.
• Private – позволяет создать процедуру, которую можно вызывать только в том модуле VBA, где данная процедура объявлена. При использовании в модуле класса дает возможность создавать личную процедуру (метод) этого класса.
Если в объявлении процедуры используется ключевое слово Static, то значения всех локальных переменных данной процедуры сохраняются между ее вызовами. Это эквивалентно использованию инструкции Static вместо Dim при объявлении каждой локальной переменной внутри процедуры.
Имя_процедуры – это любой корректный идентификатор VBA, который будет употребляться в программе в случае необходимости вызова данной процедуры.
Список_аргументов – содержит описания аргументов, которые принимаются процедурой. Описания аргументов разделяются запятой и имеют следующий формат:
[Optional] [ByVal | ByRef] [ParamArray] Имя_аргумента[()] [As Имя_типа] _
[= Значение_по_умолчанию]
Пояснения элементов, используемых в данной конструкции, приведены в табл. 1.7.
Таблица 1.7. Элементы описания аргумента процедуры
Для выхода из процедуры предусмотрена инструкция Exit Sub. При ее достижении выполнение программы немедленно переходит к инструкции, следующей за вызвавшей процедуру инструкцией.
Ниже приведен пример процедуры, имеющей два аргумента, при этом второй аргумент необязательный и передается по ссылке:
Sub ProcedureExample(ByVal intNumber As Integer, Optional fFlag = True)