Учебно-методические материалы для студентов кафедры АСОИУ

Структурные типы данных

VBA предоставляет возможность создавать и использовать сложные структуры данных на основе базовых типов. Сюда относятся массивы и пользовательский тип (user-defined type).

Структурный тип данных – это тип данных, который позволяет в одной величине хранить одновременно несколько значений. К структурным типам данных VBA относятся массивы и пользовательские типы данных.

Массивы

Массив – это упорядоченная совокупность данных одного типа (см. типы данных VBA). Порядок элементов массива задается индексами его элементов. Количество элементов определяет размер массива, а количество индексов (в VBA - до 60) - его размерность. VBA поддерживает статические и динамические массивы.

Статический массив имеет фиксированный размер и размерность, заданные при объявлении и неизменяемые в ходе выполнения программы. Синтаксис объявления статического массива:

(Public | Private | Dim) <имяМассива> (<размер1>, <размер2>, ..., <размер N>) As <типДанных> 

Указанные в скобках величины <размер1>, <размер2>, …, <размер N> задают количество индексов и максимально допустимое значение для каждого конкретного индекса (его верхняя граница). Таким образом, определяются размерность массива (количество индексов) и размер массива – количество элементов данного массива. При этом индексирование элементов массива по умолчанию начинается с нуля. Так, объявление

Dim Array1 (9) As Integer, 

определяет одномерный массив из 10 целых чисел, а объявление

Dim Array3 (4, 9) As Variant, 

определяет двумерный массив из пятидесяти (5х10) элементов типа Variant.

В VBA имеется возможность изменить индекс нижней границы с помощью оператора Option Base (указание Option Base 1 или Option Base 0 в общем разделе модуля). Более того, при объявлении массива можно явно указать и верхнюю, и нижнюю границы. Синтаксис оператора объявления массива с указанием границ для индексов:

Dim <имяМассива> (<мин1> To <макс1>[, ..., <минN> To <максN>]) As <типДанных> 

Примеры:

Dim A (1 To 3, 1 To 3) As Single Dim B (1 To 12) As Integer 

Правила инициализации элементов массива такие же, как и для переменных того типа, который использован при объявлении массива. Доступ к элементам массива выполняется по индексу. Листинг 19 иллюстрирует работу с одномерным массивом.

Листинг 19. Обращение к элементам массива

' ЗАДАЧА: Сгенерировать 10 случайных целых чисел от 0 до 100, ' записать их в массив и вывести в окно отладчика Sub sample14() Randomize Timer ' запуск генератора случайных чисел Dim myarr(1 To 10) As Long ' объявление массива ' запись чисел в массив For i = 1 To 10 myarr(i) = Round(Rnd * 100) Next ' чтение элементов массива и вывод значений в отладчик For i = 1 To 10 Debug.Print myarr(i) Next End Sub 

Удобным способом определения одномерных массивов является функция Array, преобразующая список элементов, разделенных запятыми, в массив из этих значений:

Dim A As Variant A = Array (10, 20, 30) B = A(2) 

В данном примере переменная А создается как одномерный массив, состоящий из трех элементов (10, 20, 30), а переменная В принимает значение второго элемента массива А (20).

VBA поддерживает использование динамических массивов, размер и размерность которых может изменяться во время выполнения программы. Объявление динамического массива аналогично объявлению статического, но при этом не задаются ни размер, ни размерность:

Dim <имяМассива> () As <типДанных> 

Для указания и изменения размеров такого массива используется специальный оператор - ReDim:

ReDim <имяМассива> (<размер1>, <размер2>, ..., <размер N>) 

Размерность и размер определяется динамически в той процедуре и в тот момент, когда они становится фактически известной. Обратите внимание, в этом операторе границы изменения индексов можно задать не только как константы, но и как выражения, зависимые от переменных.

Для повторных изменений массива можно снова использовать оператор переопределения ReDim. При каждом переопределении динамического массива все его значения теряются. Чтобы сохранить все ранее полученные элементы необходимо использовать ключевое слово Preserve при переопределении.

Листинг 20 демонстрирует работу с динамическим массивом (нумерация строк приведена только для удобства пояснений).

Листинг20. Работа с динамическим массивом

1: Public Vector() As Integer 2: Public Sub DMassiv() 3:	Dim N As Byte, I As Byte 4: 5: N = InputBox("Введите фактическую размерность вектора") 6: ReDim Vector(N) 7: For I = 1 To N 8: Vector(I) = 2 * I + 1 9: Next I 10: 11: 'Массив расширяется с сохранением ранее вычисленных элементов 12: ReDim Preserve Vector(2 * N + 1) 13: For I = N + 1 To 2 * N + 1 14: Vector(I) = 2 * I 15: Next I 16: Debug.Print "Элементы массива Vector:" & Chr(13) 17: For I = 1 To 2 * N + 1 18: Debug.Print Vector(I) 19: Next I 20: End Sub 

Поясним приведенный код. Сначала на уровне модуля объявляется глобальный динамический массив Vector (строка 1). В момент объявления размерность динамического массива не указывается, соответственно не выделяется память. Все это произойдет позже, в процессе выполнения программы. Далее приводится одна из возможных процедур, работающая с этим массивом Vector. В строке 12 массив переопределяется (увеличивается его размер) с сохранением предыдущих значений. Затем массив расширяется (цикл в строках 13-15). В последнем цикле (строки 17-19) значения элементов сформированного массива выводятся в окно отладки (Immediate).

В рассмотренном примере изменялся размер динамического массива, но не его размерность (массив оставался одномерным). Приведем фрагмент кода программы, в котором изменяются и размер, и размерность динамического массива:

1: Sub sample22 () 2:	Dim dArray ( ) As Variant 3: ReDim dArray(1,2) 4: dArray(0,0) = 2 5: dArray(0,1) = 3 6: k = dArray(0,0) + dArray (0,1) 7: ReDim dArray(k) 8: dArray(0) = "Строка1" 9: End Sub 

В этом примере массив dArray сначала определяется как двумерный массив из шести элементов (2x3) (строка 3), а затем переопределяется как одномерный массив, причем верхняя граница индекса задается значением k (строка 7).

Динамические массивы с успехом можно применять там, где необходимы динамические структуры данных, например списки, стеки, очереди.

Пользовательский тип данных

VBA поддерживает возможность создавать пользовательские типы данных на основе ранее определенных типов. Такой тип в VBA называется User-defined type (UDT) - тип, определенный пользователем. Это соответствует понятиям типа данных record (запись) в языке Pascal или struct (структура) в языке С/С++. Для создания пользовательского типа предназначен оператор Type. Он позволяет на уровне модуля определить структуру данных, включающую другие разнородные, но логически связанные переменные различных типов. После описания типа на его основе можно создавать и использовать переменные.

Синтаксис оператора Type:

Type <имяТипа> <имяЭлемента1> As <тип> <имяЭлемента2> As <тип> End Type 
где:
<имяТипа> – имя пользовательского типа данных;
<имяЭлемента> – имя структуры, составляющей новый тип данных.

С помощью ключевых слов Private и Public можно задать область видимости создаваемого типа. Опции Private и Public указываются в строке объявления типа перед ключевым словом Type.

Листинг 21. Пример использования пользовательского типа

' Тип TStudent хранит информацию о студенте. Public Type TStudent ID As Long 'идентификатор LastName As String 'фамилия FirstName As String 'имя MiddleName As String 'отчество BirthDay As Date 'дата рождения End Type ' Учебная группа Public Type TGroup Num As String * 10 'номер группы Students() As TStudent 'список (массив) студентов End Type ' Объявления переменных Private stud As TStudent ' студент Public group As TGroup 'группа 

Для обращения к элементам пользовательского типа (полям структуры) используется точечная нотация:

<имяПеременнойUDT>.<имяЭлемента> 

Листинг22. Работа с переменными пользовательского типа

Sub sample20() ReDim group.Students(10) group.Num = "АС-123" group.Students(0).LastName = "Петров" group.Students(0).FirstName = "Иван" Debug.Print group.Num & group.Students(0).LastName & " " & group.Students(0).FirstName End Sub 

Широкие возможности, представляемые программисту пользовательским типом имеют ограничение: все операции должны выполняться на уровне полей. Единственная разрешенная операция — присваивание (листинг 23).

Листинг 23. Операции над пользовательским типом

Sub sample21() Dim group1 As TGroup, group2 As TGroup ReDim group1.Students(25) ReDim group2.Students(28) group1.Num = "AS-123" group2.Num = "AS-456" Debug.Print "1: "; group1.Num, group2.Num ' If group2 > group1 Then ... - Это вызовет ошибку If UBound(group2.Students) > UBound(group1.Students) Then ' Так можно group1 = group2 ' Так тоже можно EndIf Debug.Print "2: "; group1.Num, group2.Num End Sub 

CC-BY-CA Анатольев А.Г., 01.10.2012