Тверской государственный университет
Опубликован: 13.09.2006 | Доступ: свободный | Студентов: 3491 / 369 | Оценка: 4.65 / 4.29 | Длительность: 30:37:00
Специальности: Программист, Менеджер
Лекция 4:

Типы данных и переменные

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >

Массивы

Простейший и самый распространенный структурный тип - массив - упорядоченная совокупность данных одного типа. Порядок на элементах массива задается индексами его элементов. В VBA массивы могут быть одномерными и многомерными. Удивительно, сколь высока допустимая размерность массива, - число измерений доходит до 60. За всю свою многолетнюю практику не припомню случая использования более чем трехмерных массивов.

Конечно, все, что было сказано о глобальных и локальных переменных, общих и закрытых, двух уровней объявления, - относится и к массивам. Появляется только единственное дополнение, связанное с необходимостью указать размерность массива и границы изменения индексов. Поэтому синтаксис объявления массивов несколько расширен, - после имени переменной в круглых скобках указывается список размерностей массива:

{Dim | Private | Public | Static }<имя переменной> (<список размерностей>) 
[ As <имя типа>]

Синтаксически каждое измерение в списке отделяется запятой и определяется заданием нижней и верхней границы изменения индексов. По историческим причинам в Бейсике нижняя граница была фиксирована и равна 0. Затем ввели специальную опцию OptionBase, позволяющую устанавливать эту границу равную 1 или 0. Подумав еще, разрешили задавать нижнюю и верхнюю границу, причем и та и другая могут быть выражениями при одном ограничении - это должны быть константные выражения, не содержащие переменных. Вот "классическое" объявление одномерного массива и работа с ним:

Public Sub MyArray()
	Const LowBound As Integer = -5, HighBound As Integer = 5
	Dim MyArr(LowBound To HighBound) As Byte
	Dim I As Integer
	Debug.Print "Элементы массива MyArr:"
	For I = LowBound To HighBound
		MyArr(I) = I + 6
		Debug.Print MyArr(I)
	Next I
End Sub

При печати элементов этого массива будут напечатаны числа от 1 до 11 по числу его элементов.

При объявлении массива всегда задавайте нижнюю границу, исходите из того, что граничная пара, задающая размерность, должна удовлетворять синтаксису:

<граничная пара> ::= <константное выражение> To <константное выражение>

Не используйте Option Base . Это ненадежное средство.

Программист Бэдли (не "наш" программист), зная, что массивы положено объявлять, дал следующее объявление:

Dim BadArr(10)

Запись получилась короткой, он написал ее быстро и был горд собой. Могу подтвердить, Бэдли действительно быстро пишет программы, жаль только, что они не всегда правильно работают. Вот еще один пример его работы:

'Option Base 0
Option Base 1
Dim Vector(10)
Dim A1(5), A2(5) As Integer
'Бэдли добавил новое объявление массива Matrix
'При работе с матрицей ему удобно было, чтобы индексы начинались с 1,
'поэтому он изменил опцию Base, отменив предыдущее соглашение
'Ранее работавшая процедура War перестала работать
Dim Matrix(10, 20) As Double

Public Sub War()
Dim i
    For i = 0 To 5
        A1(i) = i: A2(i) = i + 5
        Vector(i) = A1(i): Vector(i + 5) = A2(i)
    Next i
End Sub

Каждая строчка этого быстро написанного текста должна быть переписана при хорошем программировании.

Динамические массивы

Динамические массивы VBA это мощное средство, отсутствующее в таких известных языках как, например, С++ и Паскаль. Массив считается динамическим , если при первоначальном объявлении не указывается его размерность, но она может быть определена и переопределена в последующем оператором ReDim. Размерность определяется динамически в той процедуре и в тот момент, когда она становится фактически известной. Обратите внимание, в этом операторе границы изменения индексов можно задать не только как константы, но и как выражения, зависимые от переменных.

Если затем нужно изменить границы или размерность массива, Вы можете снова задать оператор переопределения ReDim и начать новый цикл работы с массивом. И еще одна "приятность" - можно сохранить все ранее полученные элементы и расширить массив, добавив новые элементы. Для этого надо просто задать ключевое слово Preserve при переопределении массива.

Рассмотрим пример. На уровне модуля объявим глобальный динамический массив Vector:

'Объявление динамического массива
Public Vector() As Integer

В момент объявления размерность динамического массива не указывается, соответственно не выделяется память. Все это произойдет позже, в процессе выполнения программы. Вот одна из возможных процедур, работающая с этим массивом Vector. Его размерность в момент работы с ним определяется в диалоге с пользователем. По ходу дела массив расширяется, сохраняя старые значения.

Public Sub DynArray()
    'Определяется фактическая размерность массива Vector
    Dim N As Byte, I As Byte
    N = InputBox("Введите число элементов вектора")
    ReDim Vector(1 To N)
    For I = 1 To N
        Vector(I) = 2 * I + 1
    Next I
'   Массив расширяется с сохранением ранее вычисленных элементов
    ReDim Preserve Vector(1 To 2 * N + 1)
    For I = N + 1 To 2 * N + 1
        Vector(I) = 2 * I
    Next I
    'А теперь печать
    Debug.Print "Элементы Vector:" & Chr(13)
    For I = 1 To 2 * N + 1
        Debug.Print Vector(I)
    Next I
End Sub

При печати элементов этого массива будут напечатаны, как нетрудно понять вначале нечетные числа от 3 до 21, а затем четные от 22 до 42.

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

Записи и тип, определенный программистом

Наряду с массивами, представляющими объединение элементов одного типа, существует еще один способ создания сложного типа - запись (в языке Паскаль), или структура (в языке С). Запись представляет объединение элементов, каждый из которых может иметь свой тип. Элементы записи часто называют ее полями. С объектных позиций запись - частный случай класса, в котором заданы только свойства и не определяются методы и события. Это важный частный случай, и поэтому в "хорошем" языке должна быть возможность определения записей. Чтобы с записями было удобно работать, в языке надо предусмотреть средства для определения пользовательского типа. Тогда можно отделить процесс определения структуры записи - назвать это определением пользовательского типа, скажем Т, а затем в нужном месте и в нужном количестве объявлять переменные типа Т, представляющие собой конкретные записи.

Определение каждой записи можно рассматривать, как определение дерева, с корнем которого связана сама запись, а с вершинами - потомками связаны поля этой записи. Поскольку каждое поле может быть элементом произвольного типа, в том числе записью, такие вершины имеют потомков. Благодаря вложенности запись может задавать структуру сколь угодно сложно построенного дерева, у каждой вершины которого может быть произвольное число потомков. Это статическая структура, полностью определяемая в момент объявления записи.

Что же мы имеем в VBA? Формально здесь нет понятия запись или структура, или какого-либо эквивалента. Здесь есть только тип, определенный программистом. Но поскольку он позволяет определять запись, ничего больше и не нужно. Так что записи в VBA есть, но называются они типом, определенным программистом.

При определении типа программист дает ему имя, что позволяет затем определять переменные этого типа обычным способом. Поскольку все элементы совокупности именованы, возможен прямой доступ по имени к каждому из элементов. Ниже мы будем называть переменные такого типа записями, а элементы записи - полями. Такая терминология общепринята и соответствует программистской традиции.

Синтаксис определения типа в VBA достаточно прозрачен:

[Private | Public] Type <имя типа>
	<имя элемента> [([<размерность массива>])] As <тип элемента>
	[<имя элемента> [([<размерность массива>])] As <тип элемента>]
	...
End Type

Определение типа дается на уровне модуля и, если оно является закрытым ( Private ), распространяется на один модуль, а для общих ( Public ) типов - на все. Мы ограничимся довольно стандартным примером, в котором определяются два типа (записи): Fam и Person, где одно из полей Person имеет тип Fam.

'Определение записей - пользовательских типов
Type Fam
	firstName As String
	lastName As String
End Type

Type Person
	Fio As Fam
	Birthdate As Date
End Type

Эти объявления мы поместили в раздел объявлений модуля Father. Вот одна из его процедур, использующих эти типы данных:

Public Sub UserType()
    Dim Петров As Person
    Dim Козлов As Person
    Петров.Fio.firstName = "Петр"
    Петров.Fio.lastName = "Петров"
    Петров.Birthdate = #1/23/1961#
    Козлов.Fio.firstName = Петров.Fio.firstName
    Козлов.Fio.lastName = "Козлов"
    Козлов.Birthdate = #7/21/1966#
    MsgBox (Петров.Fio.firstName & " " & Петров.Fio.lastName _
     & " родился " & Петров.Birthdate)
    MsgBox (Козлов.Fio.firstName & " " & Козлов.Fio.lastName _
    & " родился " & Козлов.Birthdate)
End Sub

Вот что будет напечатано в результате ее работы:

Петр Петров родился 23.01.61
Петр Козлов родился 21.07.66

VBA старается помочь при работе с записями, предоставляя возможность выбора полей записи из открывающегося списка. Пусть Вас не смущает форма записи дат рождения - при определении константы для дат можно задавать в более человечной форме. Например, здесь мы задавали их как #January 23, 1961# и #21 July, 66#, - они автоматически были преобразованы в формальный вид.

Что можно делать с записями?

Итак, пусть определен пользовательский тип T и объявлены переменные этого типа, например X и Y. Что можно с ними сделать? Допустимо ли присвоение ( X=Y ) или сравнение ( If (X=Y) Then Fun ), допустимы ли операции над записями? Ответ: нет, за одним исключением - присвоение допустимо, все остальное нет, в том числе и сравнение. Так что можно написать:

Петров = Козлов

Но нельзя написать:

If (Петров = Козлов) Then Debug.Print "Записи идентичны"

Отсутствие разрешенных операций над записями не означает, что с ними нельзя работать. Главное, что определен прямой доступ к полям записи, и этого достаточно, - с полями можно работать, как с переменными. Наш пример ( Sub UserType ) демонстрирует работу с полями записей.

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
полина есенкова
полина есенкова
Дмитрий Вологжин
Дмитрий Вологжин
Добрый день, прошел тесты с 1 по 9, 10 не сдал, стал читать лекцию и всё пройденные тесты с 1 по 9 сбросились, когда захотел пересдать 10 тест.