Типы данных

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

Данные в VBA характеризуются своими типами, которые определяют:

В свою очередь типы данных делятся на простые (встроенные и определяемые) и на структурные, именно в таком порядке мы и будем их описывать.

Итак, начнем с встроенных типов данных. Как и любой язык программирования высокого уровня, VBA содержит все привычные встроенные типы данных: арифметические, строковые и логические, но есть и свои типы, специфические для VBA. Полный перечень встроенных типов данных VBA с соответствующими областями значений и требуемой памятью приведен в табл. 20.2.

Тип данных Описание Область значений Требуемая память 
BooleanЛогическое значениеTrue (Истина) и False (Ложь)2 байта
ByteЧисло без знака0-2551 байт
CurrencyДесятичные числа с фиксированным количеством знаков после запятой-922 337 203 685 477,5808 - 922 337 203 685 477,58078 байтов
DateИспользуется для хранения дат1.01.0100г.-31.12.9999г.8 байтов
DecimalЛюбое число28 знаков12 байт
DoubleЧисловые значения с пла- вающей точкой двойной точности-1.7Е308--4.9Е324 для отрицательных чисел и 4.9Е324 — 1 ,7Е308 для положи- тельных чисел8 байтов
IntegerКороткие целые числовые значения-32 768 - 32 7672 байта
LongДлинные целые числовые значения-2 147483648- 21474836474 байта
ObjectСсылка на объект 4 байта
SingleЧисловые значения с плавающей точкой обыч- ной точности-3.4Е38--1.4Е45 для отрицательных чисел и 1.4Е-45-3.4Е-454 байта
StringИспользуется для хранения строковых значенийдля положительных Длина строки от 0 до 64 Кбайт1 байт на символ
VariantМожет использоваться для хранения всех вышеперечисленных типовЗначения любого из вышеперечисленных типов плюс Null, Error, Empty, Nothing.16 байт плюс 1 байт на каждый символ строковых зна- чений

Таблица 20.2. Встроенные типы данных VBA

Если такие типы данных, как integer или string не требуют особых комментариев, поскольку они стандартны и просты, то типы данных object и variant следует прокомментировать. Про тип данных object мы отдельно поговорим в разделе 20.5 "Классы и объекты", сейчас же рассмотрим уникальный в своем роде тип Variant.

Тип variant — это универсальный тип данных, позволяющий программисту не думать о том, каким будет тип переменных. С одной стороны, безусловное удобство: не надо думать при объявлении переменной, с другой — это может привести к ошибкам, которые трудно обнаружить. Более того, на обработку переменных данного типа тратится больше времени, да и память расходуется нерационально (особенно, когда речь идет о статических массивах данного типа).

Мы советуем (особенно начинающим программистам) не злоупотреблять данным типом, хотя ряд приемов его использования заметно упрощает программирование. Например, вы хотите, чтобы пользователь программы ввел целое число (после чего программа нарисует круг соответствующего радиуса) и переменную ввода целого типа. Но что, если пользователь введет вместо целого числа вещественное или, вообще, строковое значение? Произойдет ошибка при попытке присвоения переменной значения не того типа.

Вот тут-то и необходим тип Variant. Если переменная для ввода будет объявлена как variant, ничего страшного не случится: введенное значение бу дет благополучно присвоено этой переменной, а вы получите возможность проанализировать введенное значение и попросить пользователя повторить ввод, если введенное им значение не отвечает требуемым условиям. Теперь перейдем к разговору о третьей составляющей нашего определения типа данных, об операциях. Операция — это действие, выполняемое над данными.

[Результат =] операнд! <операция> операнд2 

Любая операция имеет результат и несколько операндов (как правило, два). Операнд — это элемент данных, участвующий в операции. Для каждой операции определены типы данных операндов, для которых она имеет смысл и по которым определяется тип результата. Естественен вопрос: по какому именно правилу определяется тип результата, ведь в качестве операндов могут быть операнды разных типов? Для ответа на этот вопрос необходимо ввести определение приведения. Приведение — это (автоматическое) преобразование значения одного типа в эквивалентное значение другого типа. Конечно, не всякое приведение возможно, т. е. не всегда можно сделать именно эквивалентное преобразование. Например, целое число 3 можно преобразовать в вещественное число 3.0 и значение сохранится, но вещественное число 3.1415926 нельзя преобразовать в целое, не потеряв информацию. Таким образом, учитывая приведения типов, можно однозначно определять тип результата операции по следующему правилу: если операция применяется к операндам различных типов, то операнд, у которого порядок типа ниже, преобразуется к типу операнда, у которого порядок выше и значение операции будет иметь, соответственно, тип высшего порядка. Существует четыре вида операций:

  1. Арифметические (+, - ,*, \, /, ^, mod).
  2. Логические (not, and, or, xor, eqv, imp).
  3. Строковые (+,&).
  4. Операции отношения (=, <>, <, >, <=, >=, Is, Like).

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

Переменная — это элемент данных в программе, которому присвоено имя Значение переменной может задаваться и изменяться программой (переменная — не константа), но в соответствии с определенным типом данной переменной, который задается при ее объявлении. При объявлении задается имя (для идентификации переменной в программе), затем объявляется ее тип (для определения возможных значений переменной и способов ее обработки), а также определяется область видимости этой переменной.

Явное объявление простых переменных имеет следующий синтаксис:

{ Dim I Private | Public | Static } имя Переменной [As <типДанных>] [, имяПеременной [As <типДанных>]} ...

Рассмотрим первую часть объявления — объявление области видимости переменной при помощи соответствующих ключевых слов. К сожалению, что такое область видимости переменной и время ее жизни, нельзя объяснить без специальных понятий и определений, которые будут приведены в разделе 20.4 "Структура программы". Поэтому мы не будем подробно останавливаться на этом вопросе, кроме разве мелких замечаний. Более того, данные ключевые слова несут локальную нагрузку на семантику конструкций и их пропуск при описании ни на чем не скажется.

Следующая часть объявления — это имя переменной. Правила составления имен уже достаточно подробно обсуждались в разделе 20.1 "Общие сведения", и мы не будем еще раз останавливаться на этом.

И наконец, последнее, что необходимо сделать при явном объявлении переменной, — указать ее тип, используя ключевое слово Аs, после которого идет ключевое слово, определяющее тип данных, например integer.

Помимо явного способа объявления переменной, существуют и неявные. Во-первых, можно непосредственно в имени переменной указать ее тип, добавив в конец имени специальный символ (например, $ — строка). А во-вторых, можно вообще не использовать операторы объявления, а при необходимости прямо на месте неявно вводить переменную. Например, можно сразу написать оператор d = 5. В данном случае не было предварительного (явного) объявления переменной, но все-таки она будет проинициализиро-вана. Дело в том, что по умолчанию VBA расценивает данную переменную как нестатическую типа variant. Приведем теперь программу объявления переменных.

Программа 20.3. Объявление переменных j

Dim str As String, Var = 123.456 Dim str$, k& 

Кстати, помимо явной инициализации переменных, например pi = 3.14, существует инициализация по умолчанию. То есть, когда вы объявляете переменную и не инициализируете ее, ей присваивается значение по умолчанию, так, например, для числовых типов это значение равно 0.

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

[Public I Private] Const  имяКонстанты [As ТипДанных] = выражение 

Ключевые слова Public и Private имеют такой же смысл, как и в случае с переменными. Отсутствие этих ключевых слов и описание константы внутри процедуры объявляет ее как локальную, использование же их, наоборот, объявляет ее как открытую или закрытую глобальную константу. Задание имени и типа данных аналогично случаю с переменными.

Выражение это любое значение или формула, возвращающая значение, используемое в качестве константы. Например, мы хотим ввести константу, значением которой будет площадь — const squares = 20000. Или в виде формулы (зная длину и ширину):

Const lengths = 200 Const widths = 100 Const squares = length*width 

Совет

Рекомендуется давать константам осмысленные имена и описывать их в самом начале модуля, а затем использовать всюду только именованные константы. Это делает программу не только понятнее, но и проще в сопровождении и отладке. Зачастую значение той или иной константы требуется изменить (хотя бы на время отладки), и тогда достаточно поменять лишь одно значение в описании константы. Если же в тексте программы использовалось непосредственно значение, то изменить все его вхождения намного сложнее.

В VBA, кроме констант, описываемых пользователем, существуют предопределенные встроенные константы. При именовании встроенных констант используется стандартное соглашение, позволяющее определить, к объектам какого приложения относится эта константа. Например, встроенные константы, относящиеся к Word, начинаются с букв wd, Excel — ex, PowerPoint — pp, Access — ac, VBA — vb. Например, в случае

Call Msgbox ("Использование констант", vblnformation) 

используется константа vblnformation, с помощью которой в диалоговом окне выводится значок "Информация" (рис. 20.2).

После того как выше мы описали работу с простыми типами данных, перейдем к рассмотрению более сложных — структурных типов данных. Сейчас мы рассмотрим простейший из них — массивы.

Массив — это совокупность однотипных индексированных переменных Представьте, что имеется 20 магазинов, которым издательство поставляет книгу "Microsoft Outlook 2002 в подлиннике". Естественным образом хоте лось бы иметь список, в котором было бы указано количество экземпляров, проданных каждому магазину. Данные количества для разных магазинов являются, в принципе, элементами одного типа (а точнее, просто числами). Таким образом, данная совокупность представляет собой массив. Обращение же к элементам массива происходит путем указания имени данного массива и порядкового номера требуемого элемента. Конечно, вы вправе присвоить каждому магазину персональное имя и работать с ними, как с обособленными единицами. Но представьте, что вам надо провести одну и ту же процедуру для каждого магазина, например подсчитать общее количество проданных книг. Не проще ли задать цикл для всего массива магазинов, где изменяется лишь индекс, который однозначно определяет магазин?

Количество же индексов массива в VBA может достигать 60, но это своего рода излишество, как правило, используются массивы с одним, двумя и тремя индексами. О количестве индексов массива говорят как о размерности массива. Массивы с одним индексом называют одномерными, с двумя — двумерными и т. д. Продолжив наш пример, предположим, что издательство выпускает не одну книгу, а множество различных книг, скажем, еще 100. Таким образом, вы имеете дело с двумерным массивом (20x100) и обращение к необходимому элементу становится тривиальным: магазин № 7 книга № 56. Данное обращение покажет количество проданных книг № 56 магазину № 7. Конечно, в языке VBA подобные выражения неприемлемы, но суть остается той же. Как и любой элемент данных, массив необходимо объявлять. Ниже приведен синтаксис объявления массива:

{ Dim I Private | Public | Static} имяМассива (<размер1> [, <размер2>] ...) [Аs типДанных] [, имяМассива (<размер1> [, <размер2>] ... ) [As типДанных]]

Итак, опять мы встречаем знакомые конструкции — операторы объявления массива и имя массива. Размер массива может задаваться тремя способами.

Приведем ряд примеров, поясняющих использование синтаксических конструкций. В первом из них объявляется одномерный массив типа variant с использованием ключевого слова Dim, причем индексация производится от -14 до — 1. Данная индексация имеет смысл, например, в случае с метеорологическими данными, представляющими средние дневные температуры за последние две недели. В таком случае temperature (-2) будет соответствовать позавчерашней температуре. Во втором примере показано объявление двумерного массива магазинов с использованием константных аргументов, и инициализация элемента (7, 56).

Программа 20.4. Объявление массивов

{Первый пример} Dim temperature( - 14 То -1) temperature(-2) = -10 {Второй пример} Const numbShop As Integer = 20, numbBook As Integer = 100 Dim numbBookSale (1 To numbShop, 1 To numbBook) As Integer numbBookSale(7, 56) = 300 

В приведенных примерах речь все время шла о массивах фиксированного размера, количество элементов в которых явно указано во время описания в операторе Dim. Такие массивы называются статическими. Но иногда количество элементов массива изначально не известно. Например, вы не знаете точного количества магазинов (возможно, появятся еще несколько магазинов, с которыми издательство будет сотрудничать). Как быть? Не стопорить же сбыт продукции до выявления конечного числа магазинов.

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

ReDim имяМассива (размер1[, размер2 ...]) 

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

Мы хотим ввести тип "неделя". Элементами данного типа будут только обозначения дней недели, и, соответственно, область значений будет изменяться от понедельника до воскресенья.

[Private | Public] Enum имяTипа имяЗначения [ = Константа] имяЗначения [ = Константа] End Enum 

Синтаксис довольно прост. Операторы Private и Public объявляют область видимости для типа (кстати, перечисляемые типы могут описываться только на уровне модуля, т. е. нельзя описать перечисляемый тип внутри процедуры). Затем следует ключевое слово Enum и имятипа, после чего — перечисление значений типа (по одному на строчке). По умолчанию все значения типа перенумеровываются целыми числами, начиная с 0, но вы можете самостоятельно указать константное целое значение для значений типа.

Программа 20.5. Объявление перечисляемого типа

Enum Week Monday Tuesday Wednesday Thursday Friday Saturday Sunday End Enum Sub Weekend() Dim day As Week Day = Saturday End Sub 

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

Например, мы могли бы описать человека при помощи массива целых чисел: Dim Person () As Integer, где Person (1) задает рост, Person (2) — Вес, Person(3) — объем грудной клетки и т. д. Но это все элементы одного типа integer, а как же быть когда мы захотим определить не менее важный па

раметр человека — его имя, имеющее тип string, или дату рождения типа Date? Решением является создание записи. В нашем случае это будет выглядеть следующим образом: мы создаем пользовательский тип данных Person, элементами которого являются значения разных типов. Обращение же к таким переменным строится следующим образом: Person->Weight или Person->Name

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

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

[Private |Public] Type имяТипа имяПоля [([<размер>]}] As типДанных [имяПоля [ ( [<размер>] ) ] Аs типДанных] End Type 

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

Для тех, кого последнее предложение заставило задуматься, небольшое пояснение. Определение записи можно рассматривать как дерево. Корень — это имя типа, а вершины — имена полей, которые могут являться корнями подобного же дерева. Не допускается использование рекурсивных определений, т. е. нельзя объявить тип следующим образом:

Туре Заяц Волк Аs Заяц End Type 

В приведенной ниже программе мы объявляем тип Person, имеющий поля name (имя) и birthday (дата рождения) простых типов. Далее мы объявляем тип Book, имеющий поле author определенного выше типа Person, поле title (название книги) типа string и поле content (названия глав книги), представляющее собой динамический массив типа string. После объявления типов мы объявляем одномерный массив типа Book и полностью инициализируем второй элемент массива, используя для доступа к полям записей точечную нотацию. Небольшой нюанс при инициализации поля content: поскольку это динамический массив, его необходимо переопределить. В конце просто выводится название одной из глав книги.

Программа 20.6. Объявление типов

Public Type Person name As String birthday  As  Date End Type Public Type Book author As Person title As String content () as String End Type Sub TypeExample() Dim arrBook(l) As Book arrBpok(1).author.name = "Федор Новиков" arrBook(l).author.birthday = #10/10/1951# arrBook(l).title = "Microsoft Office 2001 в целом" ReDim arrBook(1).content(0 To 1) arrBook(1).content(0) = "Введение" MsgBox (arrBook(1).content(0)) End Sub