Операторы

Любая программа представляет собой последовательность операторов. Мы уже рассматривали те операторы, которые предназначены для объявления переменных и определения типов. В этом разделе мы расскажем об операторах для выполнения действий с данными и для управления порядком выполнения других операторов. Существует три основных типа операторов: операторы присваивания, условные операторы и операторы цикла. Рассмотрим их по порядку.

Операторы присваивания необходимы для изменения значения переменных. В VBA существует четыре вида операторов присваивания:

С оператором прямого присваивания мы уже встречались (=), правда, в несколько укороченном виде.

[Let] имяПеременной = <выражение>

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

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

Dim Temp As Integer Temp = "Строка"

Встретив подобное присваивание, компилятор выдаст сообщение об ошибке. Но есть и ряд исключений. В следующей программе сначала рассматривается присваивание переменным встроенных типов стандартных значений. Затем следует объявление трех записей типа Person, после чего идет присваивание значений первым двум записям, но через прямое обращение к полям записей. В последующем же присваивании происходит одновременное присваивание значений всех полей записи peopie2 соответствующим полям записи people3.

Программа 20.7. Присваивание

Sub LetEgual()

Dim age As Integer, str$

Dim peoplel As Person, people2 As Person, peoples As Person

age = 32

str = "Жизнь прекрасна"

peoplel.name = "Александр" people2.name = peoplel.name + "a" Msgbox(people2.name) peoples = people2 Msgbox(peopleS.name) End Sub

Следующий оператор присваивания, который мы рассмотрим в данном разделе, — LSet. Он служит для специфического присваивания строк с одновременным выравниванием слева, а также для присваивания значения записи одного типа записи другого типа.

LSet имяСтроковойПвременной = СтроковоеВыражение LSet имяПеременной! = имяПеременной2

В первом случае результатом присваивания является строка той же длины, что и у значения имяСтроковойпеременной. Если значение выражения СтроковоеВыражение длиннее, то лишние символы справа удаляются, если короче — заполняются пробелами справа.

Во втором случае присваивание аналогично вышеописанному случаю с использованием оператора Let, но только здесь не обязательно, чтобы типы полей совпадали. Конечно, подобное присваивание чревато сообщениями компилятора о несоответствии типов. Мы советуем использовать данную конструкцию с очень большим вниманием.

В программе 20.8 инициализированы две строковых переменных, после чего происходит левое присваивание и вывод значения переменной str1 ("<-Влево").

Программа 20.8. Левое присваивание

Sub LsetEqual()

Dim Strl As String, Str2 As String

Strl = "0123456789"

Str2 = "<-Влево"

Lset Strl = Str2

Msgbox(Strl)

End Sub

Оператор RSet аналогичен оператору LSet, только в данном случае выравнивание происходит справа. Помимо этого, оператор RSet нельзя использовать для присваивания записей.

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

После операторов присваивания перейдем к рассмотрению операторов ветвления. Как и во многих языках программирования, в VBA имеются различные управляющие конструкции, позволяющие изменять порядок выполнения операторов программы. При отсутствии управляющих конструкций операторы программы выполняются последовательно, с первого до последнего. В некоторых простых случаях этого бывает достаточно, но обычно все-таки требуется изменить порядок выполнения операторов при выполнении определенных условий либо пропуская выполнение некоторых операторов, либо, наоборот, многократно повторяя их. Оказывается, для реализации любых алгоритмов достаточно иметь только два вида управляющих конструкций — ветвления и циклы. Первым из рассматриваемых нами операторов ветвления является стандартный условный оператор ветвления if. . .Then.. .Else. Его использование позволяет проверить некоторое условие и в зависимости от его истинности выполнить ту или иную группу операторов.

Замечание

Оператор If. . .Then. . .Else называют также условным оператором.

Для данного оператора есть два варианта синтаксиса — в одну строку и в несколько:

If условие Then [блокОлераторов1] [Else блокОператоров2] ИЛИ

If условие1 Then

[блокОператоров 1] [ElseIf условием Then

[ блокОпера торовN] ... [Else

[блокОператоров_Е1зе]] End If

Но обо всем по порядку. После ключевого слова if стоит условие. В качестве условия можно использовать логическое выражение, возвращающее значение True или False. Также можно использовать арифметическое выражение, в этом случае нулевое его значение эквивалентно False, ненулевое — True. Если условие возвращает True, то выполняется блокоператоровJ, если

False — блокОператоров2, представляющий собой последовательность разделенных двоеточием операторов. Причем необходимо наличие хотя бы одного из блоков операторов.

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

Вторая схема действует по следующему принципу. Проверяется условие1. Если оно истинно, то выполняется блокоператоров! и осуществляется переход к оператору, стоящему за ключевым словом End if. Если же оно ложно, то проверяется условие.? и т. д. Если проверка дошла до последнего оператора Eiseif и условием тоже оказывается ложным (то есть все вышестоящие условия ложны ), выполняется блокОператоров_Е1зе.

В программе 20.9 инициализируются три переменные а, ь и с. Далее показывается использование условного оператора в виде одной строки с использованием разделителя операторов — двоеточия. Поскольку проверяемое условие истинно, выполняются присваивание (с = c+1) и вывод (с = и).

В следующей конструкции проверяется условие (с > 20), т. к. условие ложно, то оператор присваивания (с = c+l) не выполняется. Далее проверяется условие (с = -а + b+ 1) — оно истинно, следовательно, выполняется вывод (с = ll). В противном случае вывелось бы "Не может быть" (что исключено).

Программа 20.9. Использование оператора if. . .Then. . .Else !

Sub branch()

Dim a, b, с

a = -10

b= 0

с = 10

If c>a Then c=c+l : MsgBox(c) Else a=a-l : MsgBox(a)

If с > 20 Then

c=c+1

ElseIf с = -a + b + 1 Then

MsgBox (c) Else

MsgBox ("He может быть")

End If

End Sub

Вышерассмотренные цепочки операторов if. . .Then.. .Eiseif обладают большой гибкостью и позволяют решить все проблемы, однако если выбор одной из нескольких возможностей все время основан на различных значениях одного и того же выражения, гораздо удобнее использовать предназна ченный для этого оператор выбора select case, имеющий следующий синтаксис:

Select Case выражение [ Case списокЗначенийN

[блокОператоровN]] ... [ Case Else

[блокОператоров_Е1зе]] End Select

Проверяемое выражение вычисляется в начале работы оператора select case. Это выражение может возвращать значение любого типа — например логическое, числовое или строковое. При выполнении оператора Select case значение проверяемого выражения вычисляется один раз и запоминается.

Далее идет список альтернатив, начинающихся ключевым словом case. В каждой альтернативе указан список значений, представляющий собой несколько возможных значений, разделенных запятой. При выполнении оператора select Case значение сравнивается со списками значений альтернатив. Элементы списка значений могут иметь одну из следующих форм:

Вся конструкция работает следующим образом. Если хотя бы один из элементов списка значений соответствует проверяемому выражению, то выполняется соответствующий блок операторов и на этом выполнение оператора Select Case заканчивается. Если же ни один из элементов всех списков альтернатив не соответствует значению проверяемого выражения, выполняется блокОператоров_Е1sе (если, конечно, присутствует ключевое слово Case Else).

В следующем примере при помощи функции inputBox переменной t присваивается некое значение, после чего посредством оператора select Case проверяется положительность значения переменной. Заметьте, что предусмотрен вариант, когда пользователь введет не число 3 .

Программа 20.10. Использование оператора Select Case

Sub branchLinef) Dim t As Integer

Использование оператора GoTo будет рассмотрено чуть ниже.

labelInput: t = InputBox{"Введите число") If (Not (IsNumeric(t))) Then

Call MsgBox("Введено не число", vbCritical)

GoTo labellnput End If

Select Case t Case 0

Msgbox ("Введен 0") Case 1 To 100

MsgBox("Введено положительное число") Case -100 To -1

MsgBox("Введено отрицательное число") Case Is < -100 , Is > 100

MsgBox("Число больше 100 или меньше -100") Case Else

MsgBox("He может быть") End Select End Sub

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

Помимо условных операторов, в VBA существует оператор безусловного перехода, который также меняет порядок выполнения операторов в программе (безусловно):

GoTo имяМетки

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

Совет

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

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

Операторы цикла VBA делятся на три группы:

Первый из рассматриваемых нами операторов цикла — For.. .Next. Данный оператор позволяет выполнять группу операторов (которая называется телом цикла) заранее определенное количество раз, при этом параметр цикла последовательно принимает ряд значений, определенных пользователем в заголовке цикла.

For счетчик = начало То конец [Step шаг]

[блокОператоров1] [Exit For]

[блокОператоров2] Next [счетчик]

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

БлокОператоров! — это блок операторов, который будет выполнен, пока счетчик не пробежит ряд значений до конца. Прервать же данный пробег вправе только оператор Exit For, предназначенный для выхода из цикла, не дожидаясь его завершения и передачи управления оператору, следующему непосредственно за Next. Как правило, оператор используется в тех местах тела цикла, где требуется из него выйти по условию.

В конце цикла ставится заключительный оператор Next, после которого указывается счетчик цикла. Хотя данное указание необязательно, мы рекомендуем всегда его использовать, поскольку программа станет более понятной, особенно в случае большого количества вложенных циклов.

Итак, рассмотрим работу конструкции цикла со счетчиком в целом. Оператор For инициализирует переменную счетчик значением начало, после чего выполняется блокОпера торов 1 до тех пор, пока не встретится оператор Exit For (выход) или оператор Next (следующий). Далее оператор Next проверяет, не достигнуто ли значение конец, и если нет, то прибавляется значение шага к счетчику и процедура повторяется, если да — работа оператора цикла завершается.

В программе 20.11 мы рассмотрим три примера работы с циклом For...Next. В первом примере мы запрограммировали решение задачи о вычислении факториала числа 20 (20!=1*2*3**20), причем значение счетчика явно используется в вычислениях. После чего вывели итоговый результат (~2,432Е+18).

Во втором примере мы показываем, что помимо простых конструкций с циклами существуют более сложные — вложенные циклы. Характерным примером для вложенных циклов является инициализация матрицы (n x m). Мы проинициализировали все элементы матрицы (6 х 5) единицей.

В последнем примере мы продемонстрируем работу оператора Exit For и счетчика с отрицательным шагом. Допустим, у нас есть проинициализирован-ный массив типа string. Необходимо найти элемент данного массива, равный строке "выход", причем проверка будет происходить с конца массива.

Программа 20.11. Использование оператора For. . .Next

Sub Factorial()

Dim factorial As Variant

factorial = 1

For i = 1 To 20

factorial = factorial * i Next

MsgBox(factorial) End Sub

Sub InitMatrix()

Dim matrix (5,4) As Integer

For i = 0 To 5

For j = 0 To 4

matrix(i, j) = 1

Next j

Next i End Sub

Sub VectorSearch

Dim Vector(7) As String

Инициализация

For i= 7 To 0 Step -1

If (Vector(i) = "Выход") Then

Exit For :

End If Next i End Sub

Теперь допустим, что вы не знаете заранее, сколько раз должно выполниться тело цикла, как в случае с оператором For.. .Next, но знаете условие, при котором цикл должен продолжать или прекращать свою работу. В таком случае и следует употреблять циклы с условием — DO ... Loop. Например, издательству поступают заявки от 25 магазинов на покупку определенного количества книги "Microsoft Office 2001 в целом", но количество книг ограничено (скажем, их всего 5000 экземпляров). Издательство, соответственно, удовлетворяет первые заявки, насколько может (то есть не более того, что есть сейчас на складе). Перед издательством встает задача — определить, заявки скольких первых магазинов оно удовлетворит? Перейдем к математической трактовке поставленной задачи. Заявки от магазинов образуют одномерный массив, элементы которого суть количества заказываемой книги. Таким образом, мы хотим узнать: сколько первых элементов этого массива можно взять так, чтобы их сумма значений была не больше 5000? В данном случае есть цикл и есть условие, но неизвестно, сколько именно раз потребуется выполнять суммирование для выявления необходимого количества элементов. Для решения подобных задач и применяется оператор цикла DO ... Loop. Существует два вида циклов с условием: с предусловием и с постусловием. Соответственно, и цикл DO ... Loop имеет две синтаксические конструкции, суть различия которых — во времени проверки условия.

/ Предусловие /

Do [{While I Until} условие]

[ блокОператоров 1] [Exit Do]

[блокОператоров2] Loop

/ Постусловие /

Do

[блокОператоров 1] [Exit Do]

[блокОператоров2] Loop [{While | Unti1} условие]

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

Теперь о проверке условий. Если в конструкции стоит ключевое слово while, то блок операторов будет выполняться, пока условие остается истинным, если же стоит until, блок операторов будет выполняться до тех пор, пока условие остается ложным. Вообще, исходя из синтаксиса, наличие условия не обязательно. Если его нет, то по умолчанию оно трактуется как False.

Необязательный оператор Exit DO аналогичен оператору Exit For в цикле For. . .Next. Он также прекращает выполнение цикла и передает управление на оператор, следующий непосредственно за Loop.

Давайте на приведенном выше примере рассмотрим работу цикла с условием. Наше условие выглядит так: "сумма > 5000", причем это условие выхода из нашего цикла, т. к. мы найдем искомое число элементов массива. Следовательно, сначала мы должны вычислить сумму (блокОператоров), а потом проверить, не больше ли она 5000 (until sumOfBooks > sooo). Помимо этого надо следить, чтобы мы не вышли за пределы границ массива, для чего используется оператор it.

Во втором примере мы решили ту же самую задачу, но несколько другим способом. Мы запустили, вообще говоря, бесконечный цикл, поскольку условие while 1 всегда истинно. Выходом же из цикла является выполнение условия sumOfBooks > 5000.

Программа 20.12. Использование оператора Do... Loop

Sub ShopCalculate(}

Dim bookshops(1 To 25} As Integer, sum As Integer

Инициализация booksShops

Первый способ

sumOfBooks = 0

numOfShops = 0

Do

numOfShops = numOfShops + 1

If numOfShops > 25 Then Exit Do

End If

sumOfBooks = sumOfBooks + bookshops(numOfShops) Loop Until sumOfBooks > 5000 MsgBox (numOfShops - 1)

Второй способ sumOfBooks = 0 numOfShops = 0 Do While 1

numOfShops = numOfShops + 1

If numOfShops > 25 Then Exit Do

sumOfBooks = sumOfBooks + bookshops(numOfShops)

If sumOfBooks > 5000 Then Exit Do Loop

MsgBox (numOfShops - 1) End Sub

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

For Each элемент In группа

[блокОператоров1] [Exit For]

[блокОператоров2] Next [элемент]

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

В следующем примере представим, что мы не знаем точного количества магазинов, они могут присоединиться или, наоборот, отказаться от услуг издательства, но (в данном случае) мы хотим подсчитать, сколько всего поступило заявок издательству. Тогда с использованием объявления динамических массивов и оператора For Each. . .Next данная проблема решается без затруднений. Заметьте, что не надо менять цикл, даже если вы исправите размерность массива, например на bookshops (25, 2) (заявки на две книги одновременно).

Программа 20.13. Использование оператора For Each. . .Next

Sub RecSum()

Dim bookshops() As Integer

Dim elem As Variant

ReDim bookshops(1 To 25)

Инициализация

sum = 0

For Each elem In bookshops

sum = sum + elem Next

MsgBox (sum) End Sub

На этом мы закончим описание операторов VBA и перейдем к рассмотрению структуры программы.