Читаем без скачивания VBA для чайников - Стив Каммингс
Шрифт:
Интервал:
Закладка:
While. . .Loop и Do Until... Loop.
Представьте себе, что вы ведете передачу по кулинарии и рассказываете своим слушателям рецепт. Вы можете сказать: "Продолжайте вымешивать масло, пока в нем заметны неоднородности" или "Продолжайте вымешивать масло до тех пор, пока оно не станет совершенно однородным". И первое, и второе означают одно и то же.
Подобным образом взаимно дополняются операторы Do While и Do Until. Если в операторе Do While условием является А = В, то эквивалентным ему оператором будет
Do Until с условием А о В.
Do или не Do
Цикл Do в своем условном выражении обеспечивает всю необходимую информацию, на основании которой VBA может принимать решение о продолжении или завершении выполнения цикла. К сожалению, в реальности дело не всегда обстоит так идеально, и иногда изменение другого условия внутри цикла требует немедленного выхода из цикла, для чего в VBA предусмотрен оператор Exit Do.
Действующий только внутри цикла Do, оператор Exit Do немедленно прекращает выполнение цикла и передает управление оператору, следующему сразу после цикла. В следующем примере выполняется конкатенация строковой переменной с некоторой имеющейся строкой, но если переменная содержит больше одного символа, цикл прекращается:
Do While strA <= "2"
If Len(strA) > 1 Then
Exit Do
End If
strB = strB & strA
strA = GetNextCharacter
Loop
Обычно необходимость в операторе Exit Do может возникнуть только во вложенных в цикл операторах If. . .Then и Select Case. В этих случаях цикл выполняется нормально до тех пор, пока не происходит что-то особое или не появляется непредусмотренное значение. Оператор Exit Do можно использовать также и для отладки, для временной отмены выполнения цикла, чтобы не размещать апостроф (') в начале строк целого блока программного кода.
В стандартных операторах Do While/Until. . . Loop условие можно проверять либо в начале, либо в конце цикла. Но что делать, если вы хотите проверить некоторое условие внутри цикла?
В этом случае используйте оператор Do... Loop без While и Until. Но при этом вам понадобится вложить в цикл либо оператор If, либо Select Case. Вложенный условный оператор может содержать оператор Exit Do, что позволит программе прекратить выполнение цикла, когда заданное условие окажется выполненным.
Вот схематическое представление оператора Do ... Loop:
Do
(операторы, выполняющиеся при каждом проходе цикла)
If условие Then
Exit Do
End If
(операторы, выполняющиеся, только если цикл продолжает выполняться)
Loop
Как видите, эта техника годится в том случае, когда нужно выполнить некоторые операторы в цикле, независимо от выполнения или невыполнения условия, а также если выполнение цикла необходимо прервать в зависимости от некоторого другого условия.
Например, часто приходится проверять правильность введенных пользователем данных относительно целого ряда критериев. В следующем примере с помощью структуры Do... Loop цикл ввода повторяется до тех пор, пока пользователь не введет правильную букву ответа:
Sub GetAnAnswer()
Dim strAnswer As String
strAnswer = InputBox("Enter your answer (A-E)")
Do
If strAnswer = "" Then
strAnswer = InputBox("You di dn't enter anything." _
& " Please type a letter between A and E.")
ElseIf Len(strAnswer] > 1 Then
strAnswer = InputBox("Your answer should be" _
& " only one letter long. Please t ry agai n.")
ElseIf strAnswer < "A" Or strAnswer > "E" Then
strAnswer = InputBox("You typed an invalid" _
& " charact er. Type a letter from A to E.")
Else
Exit Do
End If
Loop
End Sub
Эта программа выполнит оператор Exit Do только тогда, когда все три условия, заданные в операторах If n ElseIf, будут выполнены.
В качестве альтернативы для достижения той же цели можно предложить использовать Do WhiLetrue в первой строке структуры, задающей цикл. Поскольку True (константа) всегда имеет значение True, условие всегда выполняется, и, следовательно, VBA обязательно начнет и будет продолжать выполнять цикл. Поэтому, для того чтобы завершить выполнение такого цикла, внутри него должен присутствовать оператор Exit Do.
Повторение под управлением циклов For...Next
Если уже перед выполнением цикла известно, сколько раз он должен выполняться, используйте цикл For. . . Next. Число проходов цикла задается значениями начало и коней, которые могут быть целыми числами, переменными и даже сложными выражениями. В процессе выполнения цикла переменная счетчик хранит информацию о числе выполненных проходов цикла. Когда значение счетчика становится равным значению конец, выполнение цикла завершается.
Упрощенно синтаксис структуры For. . . Next можно представить так:
For счетчик = начало То конец
(операторы, выполняющиеся при каждом проходе цикла)
Next счетчик
В следующем примере для отображения сообщения при каждом проходе цикла в процедуре используется окно Immediate (в редакторе Visual Basic окно Immediate открывается нажатием клавиш <Ctrl+G>):
Sub CountToTen()
Dim j As Integer
For j = 1 To 10
Debug.Print "Дубль № " & j
Next j
End Sub
В этом примере начало и конец являются буквальными числовыми значениями. Когда цикл начинается, j получает значение 1; другими словами, переменной счетчик присваивается значение начало. После каждого прохода цикла оператор Next j увеличивает значение j (на 1) и отсылает управление снова в начало цикла. Когда j достигает значения 10, выполнение цикла прекращается.
Важные замечания по поводу циклов For.. .Next
Старайтесь, чтобы ваш программный код всегда оставался понятным. Используйте 1 в качестве начального значения для цикла For. . . Next, если только у вас нет серьезных причин выбрать для этого другое число.
Такие серьезные причины на самом деле бывают, например, когда значение счетчика используется в самом цикле (но, уточню, не меняется в цикле). Если в цикле предпринимаются некоторые действия по отношению к последовательно пронумерованным элементам типа номеров страниц, то в качестве значений для величин начало и конец можно использовать реальные значения номеров этих элементов. В частности, при работе с массивами обычно начало выбирается равным 0 (подробности - в следующем разделе).
В операторе Next счетчик, завершающем цикл For. . . Next, имя переменной-счетчика указывать не обязательно - ключевое слово Next автоматически вычислит следующее значение счетчика и отошлет VBA в начало структуры. Однако определенно стоит приучить себя включать имя счетчика в оператор Next.
Тогда даже в случае нескольких вложенных циклов For. . .Next вы всегда сможете с первого взгляда сказать, какому циклу принадлежит данный оператор Next. He меняйте значение счетчика внутри цикла For. . .Next. Поскольку счетчик является обычной переменной, можно - а иногда и заманчиво - создать программный код, меняющий значение счетчика. Не поддавайтесь!
Стоит ошибиться со счетчиком и можно пропустить пару важных шагов или заставить цикл выполняться бесконечно.
Хотя и можно значение конец для цикла For . . . Next задать переменной, изменение значения такой переменной после начала выполнения цикла не повлияет на процесс выполнения. Цикл все равно будет выполнен столько раз, сколько задано оригинальным значением конец.
Циклы For... Next и массивы
Циклы For. . .Next особенно полезны при работе с массивами, именованными хранилищами для множеств элементов данных. Подробно массивы обсуждаются в главе 13, но дискуссия о циклах For. . . Next осталась бы неполной без нескольких слов о пользе таких циклов в совокупности с этими имеющими большое практическое значение корзинами для данных.
С помощью цикла For. . .Next несложно заполнить массив множеством вычисленных значений, как в следующем примере:
Dim intМассивКвадратов (14) As Integer
For a = 0 To 14
intMacсивКвадратов( a) = a * a
Next a
Этот пример программного кода начинается с объявления массива из 15 целых значений (15, а не 14, поскольку обычно VBA приписывает первому элементу в массиве индекс 0). Затем используется цикл For . . . Next, в котором каждому элементу массива, от 0 до 14, присваивается значение. Обратите внимание на то, что переменная а используется не только как счетчик, но и как индекс массива, указывающий на номер элемента в массиве.
Вложенные циклы For... Next
Подобно другим управляющим структурам VBA, циклы For. . .Next можно вкладывать один в другой - или в другие управляющие структуры, - так глубоко, как это необходимо. Следующий совершенно бесполезный фрагмент программного кода иллюстрирует эту возможность:
Dim sngC ' наверное, C означает "случайное число"
Randomize ' инициализация генератора случайных чисел
For A = 1 To 5
sngC = Rnd()
For B = 1 To 5
Debug.Print sngC * Rnd()
Next
Next A
Если вы достаточно наблюдательны, то без труда сможете проследить за шагами, которые делает VBA в процессе выполнения этого программного кода.