2 Курс Информатика VBA(ЗО) / Книги / В.Д.Хорев - Самоучитель программирования на VBA в Microsoft Office
.pdfДанные VBA: типы данных, переменные и константы 265
И все будет работать точно так же, как и если бы предварительно была объявлена переменная SvodCount. Однако, если в результате опечатки или забывчивости, имя используемой в цикле переменной будет отличаться от имени переменной, которой предварительно присваивалось значение, то это окажутся две разные переменные, причем вторая будет автоматически инициализирована значением 0, поскольку используется в контексте, предполагающем целочисленные значения. Например:
SvodCount = 2
For A = 1 To PriceA.Range("Наименование").Rows.Count
...
SvodCaunt = SvodCount + 1
...
Next A
Предположим, в результате забывчивости или просто из-за опечатки в цикле было введено имя SvodCaunt вместо SvodCount. Никто ничего не заметит, и программа будет работать. Но работать она будет неправильно, поскольку переменная SvodCaunt будет автоматически создана помимо переменной SvodCount, и начальным значением ее будет число 0, а вовсе не 2. Значение же переменной SvodCount будет оставаться неизменным внутри цикла, хотя предполагалось, что оно будет увеличиваться на 1 в каждом проходе. Когда (и если!) будет обнаружено, что программа работает неправильно, придется искать, в чем же ошибка. Если в программе используется 2-3 переменные, которые упоминаются 2-3 десятка раз, то даже тогда придется немало потрудиться, чтобы найти подобную ошибку. Если же переменных несколько десятков и упоминаются они сотни раз, то, скорее всего, ошибку нельзя будет найти никогда — программу придется переписывать заново. Но это еще не самый худший случай, — возможно, сам факт наличия ошибки не будет обнаружен, и придется пользоваться неправильно работающей программой, пока на ошибку не укажет сама жизнь.
Директива Option Explicit
Для того чтобы Visual Basic перестал “понимать” необъявленные переменные, используют директиву Option Explicit. Эта директива помещается в начале исходного текста и любые переменные, упоминаемые после нее, обязательно должны быть предварительно объявлены. Если рассмотреть предыдущий пример с учетом директивы Option Explicit, то картина разительно переменится. Например:
Option Explicit
...
Dim SvodCount As Integer
Dim A As Integer
...
SvodCount = 2
...
For A = 1 To PriceA.Range("Наименование").Rows.Count
...
SvodCaunt = SvodCount + 1
...
Next A
При попытке запуска программы компилятор Visual Basic обнаружит ошибку и, вместо того, чтобы запустить программу, выдаст сообщение: “Ошибка компиляции: переменная не определена”, выделив при этом в тексте ошибочное имя SvodCaunt (рис. П.1).
266 Приложение. VBA, как язык программирования: данные, синтаксис и функции
Рис. П.1. Компилятор обнаружил необъявленную переменную
Опечатка обнаружена сразу же, а поиск ее не стоил программисту никакого труда.
Если создается простенький макрос “на скорую руку”, то можно не объявлять переменные и не использовать директиву Option Explicit. Но как только программа станет немного сложнее, то придется использовать директиву Option Explicit и заранее объявлять каждую переменную, поскольку в противном случае вряд ли удастся отладить программу, а если и удастся, то никогда нельзя быть уверенным в том, что она работает правильно.
Область видимости и время жизни переменных
Переменные и константы, кроме всего прочего, характеризуются областью видимости — областью, где они “видны”, то есть, доступны для программы. За пределами своей области видимости переменная или константа не может быть использована программой. Область видимости переменной или константы определяется двумя обстоятельствами: где она объявлена, и какое дополнительное ключевое слово было при этом использовано.
Предположим, в исходном тексте (это может быть модуль, форма, рабочая книга или документ), объявлены переменные A, B и C:
Public A As Integer Dim B As Integer
...
Sub MySub()
Dim C As Integer
...
End Sub
Глобальная переменная A будет доступна во всех процедурах всех модулей, относящихся к данной рабочей книге или документу.
Переменная B доступна только в пределах модуля, то есть в этом же окне исходного текста. Если где-то в другом модуле объявлена глобальная переменная с таким же именем (Public B), то в процедурах этого модуля будет фактически использована эта переменная B, а в остальных местах под B будет иметься в виду глобальная, то есть Public-переменная B.
Переменная C определена только внутри процедуры MySub. Если переменная с таким же именем объявлена на уровне модуля, то внутри процедуры MySub будет все равно использоваться “своя”, локальная переменная C.
Существует еще область видимости Private — такие переменные доступны в пределах модуля, но недоступны в других модулях. Это область видимости по умолчанию, и ее можно явно не указывать — объявление Dim на уровне модуля (то есть вне текста какой-либо процедуры) подразумевает Private.
Кроме области видимости, локальные и глобальные переменные имеют еще одно важное отличие. Глобальные переменные существуют и сохраняют свое значение все время, пока выполняется программа. Локальные переменные, объявленные внутри процедуры, существуют только во время выполнения процедуры. Например:
Данные VBA: типы данных, переменные и константы 267
Public A As Integer Dim B As Integer
...
Sub MySub()
Dim C As Integer A = 10
B = 20
C = 100
...
End Sub
После того, как процедура MySub завершит свою работу, переменная C “исчезнет” вместе со своим значением, и снова она возникнет уже со значением 0 в момент следующего вызова процедуры MySub. А переменные A и B сохранят присвоенные им значения. Причем значение A сможет прочитать процедура любого модуля, а значение B будет доступно только в пределах текущего модуля. Благодаря глобальным переменным процедуры могут передавать друг другу, или, скорее, оставлять друг для друга сохраненные данные.
Существует возможность сохранять значения локальных переменных. Если объявить переменную внутри процедуры с использованием зарезервированного слова Static, то она будет продолжать существовать и после завершения процедуры, сохраняя свое значение. Например:
Sub MySub()
Static C As Integer
...
End Sub
Массивы
Массивом называют совокупность переменных одного типа, доступ к которым осуществляется по их общему имени (имени массива) и номеру переменной в массиве (индексу). Применение массивов упрощает операции с массивами данных. Например:
Const MaxWords = 3000
Const WordsInDictionary = 200
Dim Words(0 To MaxWords) As String
Dim WordFrq(0 To MaxWords) As Integer
Если нижняя граница индекса не указана, то по умолчанию она принимается равной 0. При помощи директивы Option Base значение нижней границы по умолчанию можно изменить, например Option Base 1 задаст отсчет нижней границы по умолчанию с 1.
Таким образом, массив Words, например, можно было бы определить, как
Dim Words(3000) As String
Если бы требовалось использовать две размерности в массиве, достаточно было бы указать два набора границ:
Dim Words(0 To 30, 0 To 100) As String
Динамические массивы
В Visual Basic поддерживаются динамические массивы, то есть массивы, размерность которых меняется при выполнении программы. Например, можно было бы не указывать размерность массива Words при его объявлении:
268 Приложение. VBA, как язык программирования: данные, синтаксис и функции
Dim Words() As String
Но затем, перед первым обращением к элементам такого массива, необходимо будет задать его размерность при помощи оператора ReDim:
ReDim Words(0 To 3000)
При необходимости изменить размерность, ее снова можно переопределить:
ReDim Words(0 To 4000)
Если новая размерность больше старой, в массиве просто появятся дополнительные пустые элементы, в данном случае строки. Если новая размерность меньше старой размерности, то значения части элементов будет утеряны.
При помощи функций LBound и UBound можно получить текущие значения нижней и верхней границ динамического массива соответственно. Операторы
MsgBox LBound(Words)
MsgBox UBound(Words)
выведут на экран значения 0 и 4000.
Объектные переменные
Объектную переменную можно объявить, как абстрактный объект (тип Object), или указать
для нее определенный объектный тип. Переменная типа Object (ссылка на объект) может указы-
вать на объект любого типа.
Переменная, объявленная, как ссылка на объект определенного типа, может указывать на объект только этого типа. Присваивание ей в качестве значения объекта другого типа вызовет ошибку.
Присваивание объектного значения (точнее, ссылки на объект) производится при помощи зарезервированного слова Set:
Dim MyParagraph As Paragraph
Dim MyDocument As Document
...
Set MyDocument = Documents.Add
Set MyParagraph = MyDocument.Paragraphs.Add
С таким же успехом можно объявить обе переменные, как объект, и присвоить им в качестве значения объекты типа “документ” и “абзац”, …
Dim MyParagraph As Object
Dim MyDocument As Object
...
Set MyDocument = Documents.Add
Set MyParagraph = MyDocument.Paragraphs.Add
… или наоборот:
Set MyParagraph = Documents.Add
Set MyDocument = MyDocument.Paragraphs.Add
В любом случае при этом произойдет так называемое “позднее связывание” и фактический тип объектов MyDocument и MyParagraph определится уже в процессе выполнения программы. Такой способ работы с объектами связан с определенными сложностями, и использовать его следует только в тех случаях, когда тип возвращаемого объекта действительно заранее неизвестен.
Данные VBA: типы данных, переменные и константы 269
Определить тип объекта, ссылка на который получена откуда-то извне (например, как возвращаемое значение какой-то функции), можно при помощи оператора TypeOf и операции Is:
Dim MyObject As Object
...
Set MyObject = MyFunction()
...
If TypeOf MyObject Is Document Then
MyObject.Paragrahps.Add
...
End If
If TypeOf MyObject Is Workbook Then
MyObject.WorkSheets.Add
...
End If
Типы данных
Все данные, которыми оперирует VBA-код, относятся к определенному типу. Тип переменной можно не указывать при ее объявлении, но это не значит, что она не будет относиться ни к какому типу: просто неявным образом будет использован универсальный тип по умолчанию, именуемый
Variant.
Зачем нужно объявлять тип?
Зачем же объявлять тип переменной, если этого можно не делать? Существует, по меньшей мере, две серьезных причины для явного указания типа данных, с которыми предполагается иметь дело.
Первая причина заключается в том, что за свободу в обращении с типами приходится платить эффективностью. Если требуется переменная I для хранения целочисленных значений, то можно объявить ее с явным указанием целочисленного типа Integer:
Dim I As Integer
или же просто, как
Dim I
или, что то же самое,
Dim I As Variant
Как уже указывалось, если тип не указан, то по умолчанию используется тип Variant. Так можно делать, и программа будет нормально работать. Если таких переменных немного и обращение к ним происходит небольшое число раз, то никакой разницы программа “не почувствует”. Но разница все же есть. Переменная типа Variant занимает в несколько раз больше места в памяти
компьютера, чем переменная типа Integer, а обращение к ней происходит во много раз медленнее. Поэтому, если используются большие массивы и циклы, то переменные типа Variant способны существенно замедлить работу программы.
Вторая причина для явного указания типов всех переменных заключается во все тех же опечатках и ошибках, которые неизбежно случаются при работе с исходным текстом. Если тип переменной I, которая упоминалась выше, не указан явным образом, то можно присвоить ей любое значение, например строковое:
I = “Строковое значение”
270Приложение. VBA, как язык программирования: данные, синтаксис и функции
Втакой возможности кроется неиссякаемый источник ошибок. Например, выражение
I = “1” + “1”
никоим образом не эквивалентно выражению
I = 1 + 1
В первом случае переменная I получит строковое значение “11”, а во втором — числовое значение 2. Если тип I не указан явным образом, то оба варианта одинаково правомерны. Но если I
— это переменная типа Integer, то попытка присвоить ей строковое значение вызовет ошибку выполнения и программист обнаружит, что он что-то напутал. В противном случае поиски подобных ошибок могут стать бесконечными.
Простые типы данных
Все основные (простые) типы данных, обычно используемые в языках программирования, поддерживаются и в VBA. Рассмотрим их.
Boolean
Может принимать только значения True (Истина) или False (Ложь). Переменные типа Boolean используются главным образом при организации циклов и ветвлений — обычно они играют роль флажков, сигнализирующих о состоянии программы. Например, можно сохранить в Boolean-переменной результат логической операции, скажем, результат сравнения двух чисел:
Result As Boolean
Dim N1 As Integer
Dim N2 As Integer
...
N1 = 10
N2 = 5
...
Result = N1 > N2
...
If Result=True Then
MsgBox “Первое число больше второго!”
End If
Integer
Этим переменным можно присваивать только целочисленные значения. Наименьшее значение: –32768 Наибольшее значение: +32767
Integer-переменные отличаются малым объемом занимаемой памяти и высокой скоростью обращения. Часто их используют в качестве счетчика цикла:
Dim Counter As Integer
...
For Counter = 1 to 1000
...
Next Counter
Long
Этим переменным также можно присваивать только целочисленные значения. От Integer этот тип отличается более широким диапазоном значений.
Наименьшее значение: –2147483648
Данные VBA: типы данных, переменные и константы 271
Наибольшее значение: +2147483647
Long-переменные отличаются высокой скоростью обращения, и наилучшим образом подходят для задач целочисленной арифметики. Например:
Dim MyDistance As Long
Dim MyTotalTime As Long Dim MySpeed As Long
...
MySpeed = 2521 MyTotalTime = 811
MyDistance = MySpeed * MyTotalTime
см. об еще одном способе объявления Long-переменных в раздел “Операции со строками” этой главы.
Single
Этот тип используется для вычислений с плавающей точкой. Single-переменные обеспечивают точность до 6-го знака после десятичной точки.
Наименьшее отрицательное значение: –3.402823E+38 Наибольшее отрицательное значение: –1.401298E–45 Наименьшее положительное значение: 1.401298E–45 Наибольшее положительное значение: 3.402823E+38
Например, с помощью переменных типа Single можно выполнять вычисления с дробями:
Dim MyWeight As Single
Dim MyPrice As Single
Dim PriceToWeight As Single
...
MyWeight = 3.1
MyPrice = 121.77
PriceToWeight = MyPrice / MyWeight
Double
Этот тип также используется для вычислений с плавающей точкой. Double-переменные обеспечивают точность до 14-го знака после десятичной точки.
Наименьшее отрицательное значение: –1.79769313486232E+308 Наибольшее отрицательное значение: –4.94065645841247E–324 Наименьшее положительное значение: 4.94065645841247E–324 Наибольшее положительное значение: 1.79769313486232E+308
Тип Double используют, когда требуется обеспечить высокую точность вычислений с дробными числами. Например, вот как может выглядеть вычисление площади круга:
Dim MyPI As Double Dim MyRadius As Double Dim MySquare As Double
...
MyPI = 3.14159265358979 MyRadius = 9.79921235715865 MySquare = MyPI * MyRadius * 2
Currency
Значения денежного типа Currency используют при финансовых расчетах различного рода. Необходимо помнить, что в денежной арифметике действуют несколько иные законы, чем в
272 Приложение. VBA, как язык программирования: данные, синтаксис и функции
арифметике обычной. Если речь идет о денежных суммах, то корректность арифметических операций будет обеспечена только при использовании специального денежного типа Currency.
Наименьшее значение: –922'337'203'685'477.5808 Наибольшее значение: +922'337'203'685'477.5807
В значениях типа Currency допускается использование не более чем четырех знаков после десятичной точки. Currency-переменные отличаются высокой скоростью вычислений, поскольку для внутреннего представления данных этого типа используются целочисленные форматы.
Вот как, например, следует выполнять вычисления с денежными суммами в пересчете на валюту по курсу:
Dim MySum As Currency Dim Kurs As Currency Dim MyUSDSum As Currency
...
MySum = 123.45 Kurs = 6.77
MyUSDSum = MySum / Kurs
Date
Данные типа Date служат для операций со значениями даты-времени. Наименьшее значение: 1 января 100 года Наибольшее значение: 31 декабря 9999 года
Значения даты и времени ограничиваются символами #...# или "...", например:
MyDate = "04/02/1962"
или
MyDate = #17/04/1972#
Значения даты и времени имеют внутреннее представление в виде числа с десятичной дробью, при этом целая часть числа соответствует дате, а дробная — времени. Это позволяет использовать операции сложения и вычитания в отношении дат и времени. Такие особенности, как разное количество дней в разных месяцах, а также особенности високосного года, учитываются автоматически. Вот пример вычисления со значениями даты — на экран выводится сообщение о количестве дней, прошедших со дня рождения:
Dim BirthDay As Date
Dim TodayDay As Date
Dim DaysAge As Long
BirthDay = "17/04/1972"
TodayDay = #26/01/2001#
DaysAge = TodayDay - BirthDay
MsgBox DaysAge
String
Для выполнения действий с текстовыми строками используют переменные типа String. Максимальная длина строки: 2 миллиарда символов. Строковые значения необходимо заключать в кавычки:
Dim MyString As String
MyString = "Строковое значение"
Данные VBA: типы данных, переменные и константы 273
Специальным видом строки является строка фиксированной длины. Ее максимальная длина равняется 65536 символов (конкретная длина указывается при объявлении). Обращение со строками фиксированной длины отличается некоторыми особенностями. Например:
Dim MyString1 As String
Dim MyString2 As String *30
MyString1 = "Строковое значение1"
MyString2 = "Строковое значение2"
В результате переменная MyString1 содержит строку “Строковое значение1”, состоящую ровно из 19 символов, а в переменной MyString2 содержится строка длиной ровно 30 символов. При этом первые 19 символов — это “Строковое значение2”, а следующие 11 позиций заполнены пробелами. На операции со строками фиксированной длины накладывается ряд ограничений, поэтому их используют только в специальных случаях.
Variant
Переменная типа Variant способна принять значение любого из простых типов. Причем конкретный тип значения, которое принимает переменная, определяется в момент присваивания. Variant — тип по умолчанию для всех переменных, которые не были объявлены или же были объявлены без указания типа.
Variant-переменная занимает больше места в памяти, чем переменная любого простого типа, чьи функции способна выполнять Variant-переменная. Применения этого типа следует по возможности избегать, поскольку обращение к данным типа Variant происходит медленнее, места в памяти они занимают больше, а программу с их использованием труднее отлаживать. Например:
Dim MyFloat As Variant
Dim MyInteger As Variant
Dim MyText As Variant
MyInteger = 19
MyFloat = 2.001
MyText = MyInteger * MyFloat & " попугаев"
В результате в переменной MyText окажется строковое значение “38,019 попугаев”, причем строка “38,019” получилась неявным образом из числа 38,019, которое, в свою очередь, получено в результате операции умножения целого числа 19 и числа с плавающей точкой 2.001.
Типы данных, определяемые пользователем
Определяемые пользователем типы данных называют также записями или структурами. Такой тип представляет собой некую совокупность типов (простых или определенных ранее), объединенных общим именем. Если затем объявить переменную, принадлежащую к вновь определенному типу, то доступ к ее компонентам можно будет осуществлять по имени переменной и, отделенному точкой, имени компоненты, каким оно было задано при объявлении типа. В отличие от массивов такой механизм позволяет объединять в единую структуру переменные разных типов.
Предположим, требуется создать специальный пользовательский тип для процедуры, которая будет обрабатывать личные данные сотрудников фирмы. В этом случае необходимо объявить тип (назовем его, например, Sotrudnik) на уровне модуля, то есть вне текста процедуры, которая его использует:
Private Type Sotrudnik
PersNum As Long
Name As String
274 Приложение. VBA, как язык программирования: данные, синтаксис и функции
BirthDay As Date
Salary As Currency
End Type
После этого можно использовать в процедуре тип Sotrudnik точно так же, как и любой простой тип. Например, можно объявить две переменные этого типа:
Dim MySotrudnik1 As Sotrudnik
Dim MySotrudnik2 As Sotrudnik
Для того чтобы присвоить значения компонентам переменной MySotrudnik1, необходимо через точку указывать имя соответствующей компоненты:
MySotrudnik1.PersNum = 121
MySotrudnik1.Name = "Евгения"
MySotrudnik1.BirthDay = "26/01/2000"
MySotrudnik1.Salary = 7900.11
Далее можно обращаться с переменной MySotrudnik1, как с единым целым. Например, присвоить ее значение переменной такого же типа:
MySotrudnik2 = MySotrudnik1
В результате выражение MySotrudnik2.BirthDay вернет значение даты "26/01/2000".
Синтаксические конструкции языка VBA
В простейших случаях, когда не происходит общения с пользователем или операционной системой, не выполняются сложные преобразования данных, программирование сводится к построению выражений, которые участвуют в операциях присваивания, и управлению ходом выполнения программы при помощи специальных операторов и функций, которые передают управление различным фрагментам кода в зависимости от выполнения тех или иных условий.
Выражения и операции
Если переменная — это то, что может находиться в левой части оператора присваивания, то выражение — это то, что может находиться в правой части оператора присваивания.
Под выражением в Visual Basic понимают другую переменную, функцию, свойство некоторого объекта или значение (числовое, строковое и т.д.), или результат разрешенных над соответствующими типами данных операций. Конечно, тип операндов и результата должен быть совместимым с типом переменной.
Арифметические операции
Арифметические операции выполняются над числовыми значениями. Их результатом также является числовое значение. В качестве операндов могут выступать переменные, константы и выражения. В табл. П.1 приведен набор арифметических операций, допустимых в VBA-программах:
ТАБЛИЦА П.1. АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ VBA
Операция Описание
+Сложение
–Вычитание или перемена знака
/Деление
*Умножение
^Возведение в степень