Циклы


В VB .NET, как практически во всех языках программирования, существуют циклы — конструкции, позволяющие выполнять операции заданное количество раз или продолжать, пока выполняется (или наоборот, не выполняется) некоторое логическое условие. По сравнению с прежними версиями VB синтаксис циклов мало изменился. В частности, изменилась конструкция While/Wend, но это изменение к лучшему.
 
Цикл с определенным условием
Цикл, выполняемый заданное количество раз, определяется при помощи ключевых слов For и Next. Например, следующая программа выводит в консольном окне числа от 1 до 10:
Sub Main()
Dim i As Integer
For i = 1 To 10
Console.WriteLine(i)
Next 1
Console.ReadLine()
End Sub
Обычно переменной-счетчику присваивается начальное значение, после чего проверяется, не превышает ли текущее значение счетчика конечное. Если счетчик превысил конечное значение, тело цикла не выполняется. Если текущее значение меньше конечного, VB .NET выполняет последующие команды до тех пор, пока не встретит ключевое слово Next (указывать имя переменной в команде Next необязательно). По умолчанию счетчик увеличивается на 1, и все начинается заново. Процесс продолжается до тех пор, пока при очередной проверке не окажется, что счетчик превысил конечное значение. В этот момент цикл завершается, и управление передается следующей за ним команде.
Хотя в качестве счетчика может использоваться числовая переменная любого типа, ре-комендуется использовать переменные типа Integer. В этом случае VB .NET тратит минимальное количество времени на изменение счетчика, что ускоряет выполнение цикла.
Единичное приращение счетчика, используемое по умолчанию, иногда неудобно—в некоторых ситуациях счетчик должен изменяться на 2, на дробную величину или в обратном направлении. Как и во всех прежних версиях VB, нестандартное приращение указывается в цикле For-Next с ключевым словом Step.
Следующая программа имитирует обратный отсчет перед запуском космического корабля:
Sub Main()
Dim i As Integer
For i = 10 To 1 Step =1
Console.WriteLine("It's t minus " & i & " and counting.")
Next i
Console.WriteLine("Blastoff!")
Console. ReadLine()
End Sub
При отрицательном приращении тело цикла For-Next игнорируется в том случае, если начальное значение счетчика меньше конечного. Это очень удобно при выполнении таких операций, как удаление элементов из списка. Если бы отсчет велся от 0 до ListCount, то на середине произошло бы обращение к удаленному элементу, тогда как при отсчете от ListCount до 0 с шагом -1 элементы нормально удаляются от последнего к первому.
Значение Step может относиться к любому числовому типу. Пример:
for yearlylnterest = .07 То .09 Step .00125D
Цикл перебирает значения от 7 до 9 процентов с приращением в 1/8 процента. Обратите внимание на использование типа Decimal для предотвращения ошибок округления.
VB .NET, как и прежние версии VB, позволяет создавать вложенные циклы практически неограниченной глубины. Следующий фрагмент выводит таблицу умножения с простейшим форматированием:
Sub Main()
Dim i, j As Integer
For j = 2 To 12
For i = 2 To 12
Console.Writed * j & " ")
Next i
Console. WriteLine()
Next j
Console ReadLine()
End Sub
Во внутреннем цикле вместо метода WriteLine используется метод Write, чтобы избежать перевода строки при выводе соседних элементов.
 
Циклы с неопределенным условием
Довольно часто условие продолжения цикла зависит от результатов, полученных в теле цикла. Следующая конструкция используется в VB .NET для построения цикла с неопределенным условием, тело которого выполняется минимум один раз (завершающая проверка):
Do
' Команды VB .NET (0 и более)
Until условие_выполняется
Конечно, условие не ограничивается простой проверкой равенства. В вашем распоряжении операторы сравнения, перечисленные в табл.3.10.
Таблица 3.10. Операторы сравнения


Символ

Проверяемое условие

<> 

Не равно

Меньше

<=

Меньше или равно

Больше

>=

Больше или равно

Строковые операнды по умолчанию сравниваются в соответствии с порядком символов Unicode. Таким образом, «А» предшествует «В», но «В» предшествует «а» (а пробел предшествует любому печатному символу). Строка «aBCD» предшествует строке «CDE» (то есть считается «меньше» ее), поскольку прописные буквы в кодировке стоят раньше строчных.
Как и в VB6, вы можете игнорировать регистр символов во всех сравнениях модуля или формы; для этого в начало модуля или формы включается команда Option Compare Text. Команда Option Compare Binary возвращается к стандартному сравнению строк в соответствии с положением символов в кодировке ANSI. При активном режиме Option Compare Text используется порядок символов для страны, указанной при установке системы Windows.
Ключевое слово Unti 1 можно заменить ключевым словом Whi I e (при этом следует заменить условие на противоположное). Например, фрагмент
Do
' Команды VB .NET (0 и более)
Loop Until X <> String.Empty
эквивалентен следующему фрагменту:
Do
' Команды VB .NET (0 и более)
Loop While X = String.Empty
Обратите внимание на использование константы String.Empty вместо пустой строки "", менее наглядной и чаще приводящей к ошибкам. Если переместить ключевое слово Whi 1е или Unti 1 в секцию Do, проверка будет выполняться в начале цикла (и при ложном условии цикл не будет выполнен ни одного раза). Пример:
Do While Text1.Text <> String.Empty
' Обработать непустой текст Loop
Условия объединяются при помощи операторов Or, Not и And. Пример:
Do While count < 20 And savings < 1000000
Если вы предпочитаете использовать старую конструкцию While-Wend, учтите, что клю-чевое слово Wend было заменено командой End While.
 
Условные команды и принятие решений
" В VB .NET условная команда If, как и в VB6, существует в двух версиях — однострочной и многострочной:
If X < 0 Then Console.WriteLine("Number must be positive!")
Условие конструкции If-Then может содержать логические операторы And, Or и Not. Довольно часто программа выполняет разные действия в зависимости от того, окажется ли условие истинным или ложным. В этом случае базовая форма команды
If-Then:
If условие Then
' Команды VB .NET (0 и более) End If
дополняется одной или несколькими секциями El se:
If условие Then
' Команды VB .NET (0 и более) Else
' Команды VB .NET (0 и более)
End If
Несколько последовательных проверок в секциях Else можно оформить в виде конструкции Elself:
If условие Then
' Команды
Elself условие Then
' Команды
Elself условие Then
' Команды
Else
' Команды
End If
Конструкция If-Then может использоваться для преждевременного выхода из цикла — для этого она объединяется с командой Exit Do или Exit For. Встретив команду Exit Do или Exit For, VB .NET немедленно завершает цикл и продолжает выполнение программы с команды, следующей за ключевым словом Loop или Next (в зависимости от типа цикла).
 
Изменения в видимости переменных
Область видимости переменных и методов в VB .NET определяется по более сложным правилам, чем в прежних версиях VB. Эта тема подробно описана в главах 4 и 5. В частности, изменения проявляются при объявлении переменных в теле цикла или блока If-Then. Такие переменные невидимы за пределами блока, в котором они были объявлены. Например, в следующем фрагменте мы выбираем одну из двух версий строковой переменной Ri sk и затем пытаемся использовать ее:
If income < 100000 Then
Dim risk As String = "too much risk" Else
Dim risk As String = "love to make a deal"
End If
Console.WriteLine("Your risk level is " & Risk)
На экране появляется сообщение об ошибке:
The name 'risk' is not declared.
Видимость обеих версий переменной risk ограничивается блоком, в котором они были объявлены! Мораль: не объявляйте переменные внутри блоков, если для этого нет веских причин.
 
Ускоренная проверка
Если компилятор обнаруживает, что проверенная часть сложного логического условия однозначно определяет результат, он не проверяет остаток выражения. Это называется ускоренной проверкой (short curcuiting). Например, если в следующем примере переменная foo ложна, компилятор не проверяет переменную bar:
If foo And bar Then...
Так было в VB .NET бета-версии 1, но в прежних версиях VB ускоренная проверка не применялась. После многочисленных жалоб разработчики Microsoft вернули старую интерпретацию логических операторов And и Or и добавили новые ключевые слова AndAlso и OrElse, поддерживающие ускоренную проверку:
If foo AndAlso Then...
 
Select Case
В качестве альтернативы для громоздких конструкций с множеством Elself в VB .NET была сохранена команда Select Case, упрощающая принятие решений в зависимости от состояния числовой или строковой переменной. Пример:
Select Case average
Case Is > 90
Console.WriteLine("A")
Case Is > 80
Console. Wri teLi ne("B")
Case Is > 70
Console.WriteLine("C")
Case Else
Console.WriteLine("You fail")
End Select
Программисты с опытом работы на С и Java, обратите внимание — команда break не нужна, поскольку выполняется только одна секция Case. Дискретные наборы значений перечисляются через запятую, а ключевое слово То позволяет задавать интервалы:
Select Case yourChoice
Case 1 To 9
' Порядок
Case -1. 0
' Неправильный ввод
End Select
 
GoTo
Говоря об управляющих конструкциях, нельзя обойти вниманием команду GoTo. Если перефразировать старую шутку, современные программисты делятся на три группы: те, кто не знает, как пользоваться GoTo, и знать не хочет; те, кто не знает, но переживает по этому поводу; и те, кто умеет ею пользоваться.
Частое использование GoTo приводит к многократным передачам управления и порождает «спагетти-код», который трудно читать и отлаживать. С другой стороны, в некоторые ситуациях применение GoTo делает программу более понятной и логичной — например, если в какой-то ситуации потребовалось выйти сразу из нескольких вложенных циклов. Команда Exit для этого не подходит, поскольку она завершает только текущий цикл.
В данной ситуации вместо Goto можно воспользоваться перехватом исключений (см. главу 7), но некоторые программисты предпочитают классический подход.
Чтобы воспользоваться командой GoTo в VB .NET, необходимо присвоить метку соответствующей строке. Метка начинается в первой позиции строки, ее первым символом является буква, а последним — двоеточие. Старайтесь присваивать меткам содержательные имена. Пример:
Bad-Input:
' Фрагмент, выполняемый при переходе
Предположим, в нашей программе данные вводятся во вложенном цикле For. Чтобы завершить ввод, пользователь вводит ZZZ :
SubMain()
Dim getData As String
Dim i, j As Integer
For i = 1 To 10
For j = 1 To 100
Console.Write("Type the data, hit the Enter key between " & _
"ZZZ to end: ") getData = Console. ReadLine()
If getData = "ZZZ" Then
Goto Bad Input Else
' Обработка данных
End If
Next j
Next i
Exit Sub
BadInput:
Console.WriteLine("Data entry ended at user request")
Console. ReadLine()
End Sub
Выходить из вложенного цикла командой Exit For неудобно — нам пришлось бы писать дополнительный код для выхода из внешнего цикла. Обратите внимание: команда Exi t Sub предотвращает передачу управления помеченному коду после завершения обоих циклов.
 
Логические операторы
Начиная с бета-версии 2 логические операторы (Not, And, Or и т. д.) работают на уровне двоичных разрядов, как и в прежних версиях VB. Допустим, у вас имеются два целых числа X и Y. Каждый бит результата X And Y равен 1 лишь в том случае, если равны 1 соответствующие биты обоих операндов; в противном случае бит результата равен нулю. Таким образом, при вычислении результата X And Y вычисляется каждый бит 32-разрядного целого числа. Пример:
X = 7 'В двоичном представлении = 0111
Y = 12 'В двоичном представлении = 1100
Выражение X And Y в двоичной системе равно 0100 (4 в десятичной системе), поскольку лишь во второй позиции оба бита равны 1. Остальные биты результата равны 0, поскольку в этих позициях хотя бы один из битов операндов равен 0. Этот способ позволяет проверить значения отдельных битов целого числа. Примеры:
(X And 1) = 1: проверить, установлен ли младший бит числа.
(X And 2) о 2: проверить, установлен ли предпоследний бит числа (поскольку в
двоичной системе число 2 представляется записью 10).
X And 255: младший байт числа (255 дес. = 11111111 дв.).
X And 65280: старший байт числа (65280 дес. = 1111111100000000 дв.).
Значение, предназначенное для проверки отдельных битов числа, называется маской (mask).
 
Массивы
В VB .NET имена массивов должны подчиняться тем же правилам, что и имена переменных. Ссылка на элемент массива выглядит как имя массива, за которым в круглых скобках указывается индекс.
Массивы VB .NET во многом отличаются от массивов VB6. Одни изменения видны сразу, другие не столь очевидны. Наиболее заметные изменения перечислены ниже.

  • Индексация-элементов в массивах начинается с 0. На момент написания книги ключевое слово То не поддерживалось — будем надеяться, что оно еще вернется!

Начиная с бета-версии 2 объявление 01m stri ngLi st(7) создает массив из восьми элементов с индексами от 0 до 7. Поскольку в VB .NET индексация всегда начинается с нуля, третий элемент массива обозначается stri ngList(2), а предшествующие элементы обозначаются stringList(0) и stringList(l).

  • Все массивы VB .NET являются динамическими. Во время работы программы их можно переобъявить с новым размером при помощи команд ReDim (с потерей текущего содержимого) и ReDim Preserve (с сохранением текущего содержимого). Пример:

Dim x() As Single
ReDim x(20) ' Начиная с бета-версии 2. создает массив из 21 элемента
ReDim Preserve x(50) ' 21 элемент сохраняется в массиве.
Команда ReDim не позволяет изменять тип массива; также не допускается использование ReDim при объявлении. Перед вызовом ReDim массив должен быть объявлен при помощи Dim или аналогичной команды.

  • Массивы могут инициализироваться при объявлении, как показывает следующий пример:

Dim weekend() As String = {Saturday. Sunday}
Менее очевидные изменения обусловлены тем, что массивы VB .NET являются экземплярами класса Array. Подробности будут рассмотрены в главе 4, а пока достаточно указать, что это позволяет выполнять операции с массивами вызовом методов класса Array. Ниже продемонстрирован пример сортировки массива методом Sort:
Sub Main()
Dim stuff() As Integer = (9. 7, 5, 4, 2. 1, -37, 6}
Array.Sort(stuff)
Dim i As Integer
For i = 0 To UBound(stuff)
Console.WriteLine(stuff(i))
Next
Console. ReadLine()
End Sub
Программа выводит массив, отсортированный с применением чрезвычайно эффективного алгоритма «быстрой сортировки».
VB.NET наследует от .NET Framework некоторые очень полезные структуры данных, возможности которых выходят далеко за рамки обычных массивов. На фоне этих структур коллекции VB5 и последующих версий выглядят примитивно. В частности, списковые массивы (с динамически изменяемыми размерами) и ассоциативные массивы (с доступом к данным по ключу) часто оказываются удобнее обычных массивов. Многие из новых структур данных рассматриваются в главах 5 и 6.
 
Массивы с индексацией элементов в заданном интервале
Утверждение о том, что индексация массивов всегда начинается с 0, не совсем точно. Теоретически можно определять массивы с заданной верхней и нижней границей индекса, но из-за неудобного синтаксиса и снижения быстродействия вряд ли вам захочется это делать. В следующем фрагменте создается массив с индексацией элементов от 1995 до 2002:
Sub Main()
Dim anArray As Array
Dim i As Integer
Dim i(0) As Integer
Dim lowerBounds(0) As Integer
i(O) = 7
lowerBounds(0) = 1995 ' Создать массив с индексами 1995 - 2002
аnАrrау = Array.CreateInstance(GetType(System.Int32). 1. lowerBounds) anArray.SetValue(200000, 1995) anArray.SetValue(1000000. 2001)
Console.WriteLine("The entry in position 1995 is " & _ (anArray.GetValue(1995).ToString))
Console.WriteLine("The entry in position 2002 is " & _ (anArray.GetValue(2001).ToString))
Console. ReadLine()
End Sub
Присваивание выполняется методом SetValue (значение,индекс), а чтение — методом GetValue(индекс). Но если массив создается подобным образом в режиме жесткой проверки типов, вам придется позаботиться о том, чтобы присваиваемое значение было преобразовано к правильному типу!
 
Цикл For-Each
Содержимое массива часто перебирается в цикле от 0 до UBound(массив), однако вы также можете воспользоваться конструкцией For-Each. Синтаксис For-Each выглядит следующим образом:
For Each переменная In массив
[команды]
[Exit For при необходимости]
[команды] Next
Конструкция For-Each универсальна и может использоваться в тех случаях, когда структура данных поддерживает итеративный перебор элементов. За подробностями обращайтесь к главе 4.
Microsoft утверждает, что применение For-Each не будет приводить к существенному снижению быстродействия по сравнению с For-Next (как это было в VB6).
 
Многомерные массивы
Массивы не ограничиваются одним измерением. Допустим, вы хотите сохранить таблицу умножения в матричном виде. Примерное решение может выглядеть так:
Dim mulTable(11.11) As Integer
' Создает массив 12x12
Dim i As Integer, j As Integer
For i = 0 To 11
For j = 0 To 11
mulTable(i.j) = (i+l)*(j+l)
Next j
Next i
Размеры массивов в VB .NET могут изменяться, но количество измерений должно оставаться постоянным.
Многомерный массив с неопределенным количеством элементов объявляется при помощи запятых. Следующий пример показывает, как объявить трехмерный массив:
Dim salesByDivision( , , ) As Decimal
Команда ReDim задает или изменяет количество элементов в каждом измерении, но размерность массива не изменяется.
При сохранении содержимого массива командой ReDim Preserve допускается изменение количества элементов только в последнем измерении массива.
 
Процедуры и функции
Раньше выбор между процедурой (Sub) и функцией (Function) определялся простым критерием: если вы собирались использовать возвращаемое значение, следовало выбирать функцию, а если нет — процедуру. Мы рекомендуем придерживаться этой модели, хотя ничто не мешает проигнорировать возвращаемое значение функции. В объектно-ориентированных программах функции и процедуры обычно включаются в классы и называются методами.
В VB .NET, как и во многих языках программирования, существуют два способа передачи параметров функциям и процедурам: передача по ссылке и передача по значению. Когда параметр передается по ссылке, его изменения внутри функции приведут к изменению исходного аргумента после выхода из функции. По умолчанию в VB .NET параметры передаются по значению (а в VB6 — по ссылке).
Было бы наивно полагать, что при передаче по значению исходный аргумент после выхода из функции всегда сохраняет прежнее значение. В VB .NET состояние объекта может измениться даже в том случае, если он передавался по значению. В главе 4 эта ситуация, часто приводящая к возникновению хитроумных ошибок, рассматривается более подробно.
 
Функции
Чтобы создать новую функцию или процедуру в окне программы, установите курсор за пределами других процедур и функций и начинайте вводить заголовок процедуры или функции. Как только вы нажмете клавишу Enter, редактор IDE автоматически создаст команду End правильного типа (End Functi on или End Sub). Ниже приведен заголовок функции, которая получает целый параметр по значению и возвращает логическую величину (True или False) в зависимости от того, принадлежит ли переданный параметр интервалу от 1 до 10: Function IsBetweenlAnd10(ByVal num As Integer) As Boolean
В режиме жесткой проверки типов (Option Strict) при объявлении функции необходимо указывать тип возвращаемого значения (в нашем примере — Boolean).
Полный текст модуля с функций Is Between lAnd 10 приведен ниже. Порядок следования функций не важен — функция Sub Mai n может находиться и после определения функции, которая в ней используется.
Module Modulel
Function IsBetweenlAnd10 (ByVal num As Integer) As Boolean
If num >= 1 And num <=10 Then
Return True
Else
Return False
End If
End Function
Sub Main()
Console. WriteLinedsBetweenlAnd100))
Console. ReadLine()
End Sub
End Module
В VB .NET при вызове функции или процедуры непустой список параметров всегда заключается в круглые скобки, как в строке с вызовом Console.WriteLine: IsBetweenlAnd100)
Обратите внимание на ключевое слово Return. При выполнении команды Return функция завершается и возвращает значение, указанное после Return (значение должно быть определенным — возвращение аналога voi d не допускается). Также поддерживается синтаксис с присваиванием имени функции, использовавшийся в прежних версиях VB:
Function IsBetweenlAnd10(ByVal num As Integer) As Boolean
If num >= 1 And num <= 10 Then
IsBetweenlAnd10 = True Else
IsBetweenlAnd10= False

End If
End Function
Использование Return — дело вкуса. Команда Return нагляднее и проще, но старый синтаксис оставляет управление внутри функции, а это иногда бывает удобно.
Обобщенная форма определения функции выглядит следующим образом:
Function имя_функции (аргумент1, аргумент2, ...) As тип
команды
Return выражение ' или имя_функции = выражение
End Function
где аргумент1 и аргумент2 — переменные. Имена функций подчиняются тем же правилам, что и имена переменных. При вызове функции VB .NET выполняет команды, содержащиеся в определении функции. Значение, указанное после Return (или последнее значение, присвоенное имени функции), определяет результат вызова.
Хотя возвращаемое значение обычно используется в программе, VB также позволяет вызвать функцию простой командой вида foo(3) без присваивания.
Обычно количество аргументов, передаваемых при вызове функции, должно совпадать с количеством параметров в ее определении. Типы аргументов должны быть совместимы с типами соответствующих параметров, при этом автоматически выполняются только расширяющие преобразования. Например, следующий фрагмент допустим, поскольку преобразование Short в Integer не приводит к потере данных:
Dim bar As Short = 3
Console.WriteLinedsBetweenlAnd10(bar))
VB .NET позволяет создавать функции с переменным числом аргументов. Дополнительная информация приведена далее в этой главе.
 
Процедуры
В отличие от функций, процедуры не возвращают конкретных значений. Вызов процедур осуществляется по имени. Непустые списки аргументов всегда заключаются в круглые скобки. В приведенном ниже примере строка с вызовом процедуры выделена жирным шрифтом:
Option Strict On
Module Modulel
Sub ShowBottlesOfBeer(ByVal nbot As Integer)
Console.WriteLine(nbot & " bottles of beer on the wall")
Console.Writeline(nbot & " bottles of beer.")
Console.WriteLine("if one of those bottles hsould happen to fall")
Console.WriteLine(nbot -1&" bottles of beer on the wall")
End Sub
Sub Main()
Dim I As Integer
For I = 10 To 1 Step -1
ShowBottlesOfBeer(I)
Next
Console.WriteLine("All beer gone...")
Console. ReadLine()
End Sub
End Module
При вызове процедур указывать ключевое слово Sub не обязательно. Строку с вызовом процедуры из приведенного выше примера можно было записать и в таком виде:
Call ShowBottlesOfBeer(I)
Заголовок процедуры должен содержать объявления всех параметров с ключевыми словами ByVal или ByRef (по умолчанию используется ByVal, то есть передача по значению):
Sub имя_процедуры(В(ByVа1 аргумент1 As тип. ByVal аргумент2 As тип, ....)
команды
End Sub
При вызове процедуры в форме имя_процедуры(аргумент1, аргумент2, ...) или Call имя_процедуры(аргумент1. аргумент2, ...) VB .NET создает копии данных-аргументов и выполняет код, содержащийся в теле процедуры (поскольку в отличие от предыдущих версий по умолчанию параметры передаются по значению).
 
Преждевременный выход из функций или процедур
В некоторых ситуациях требуется покинуть функцию до того, как будет достигнута стандартная точка выхода (например, если проверка покажет, что исходные данные неверны и дальнейшие вычисления бессмысленны). Команда Return немедленно передает управление вызывающей стороне:
Function BallOut (X As Double) As Double If X < 0 Then
Return 0' Вернуть фиктивное значение Else
' Основные действия
End If
End Function
'Выход из процедур осуществляется командой
Exit Sub.
 
Передача массивов функциям и процедурам
В VB .NET, как и в прежних версиях VB, существуют удобные средства для работы с одномерными и многомерными массивами в процедурах и функциях. Впрочем, существуют некоторые нюансы, обусловленные передачей по ссылке и по значению; мы рассмотрим их в главе 4. Перебор содержимого массива осуществляется конструкцией For Each или (более распространенный вариант) стандартным циклом For с вычислением верхней границы при помощи функции UBound (). Ниже приведен пример функции поиска максимального элемента в массиве:
Function FindMax(ByVa1 a() As Integer
Dim finish As Integer = UBound(a)
Dim max As Integer = a(0)
Dim i As Integer
For i = 0 To finish
If a(i) > max Then max = a(i)
Next i
Return max End Function
Обобщенная форма вызова UBound(имя_массива, I) возвращает верхнюю границу по 1-му измерению массива. Для одномерных массивов (списков) параметр 1 является необязательным.
Для проверки также можно воспользоваться методом Length, реализованным в классе массива, но этот метод возвращает количество элементов в массиве вместо верхней границы (в многомерных массивах эти величины не совпадают).
 
Процедуры и функции с необязательными аргументами
В VB. NET сохранена возможность определения процедур и функций с необязательными аргументами, но в отличие от VB6 для каждого необязательного параметра должно быть указано значение по умолчанию. Следующий пример демонстрирует синтаксис объявления необязательных параметров:
Sub ProcessAddress(TheName As String,
Address As String. City As String. State As String.
ZipCode As String. Optional ZipPlus4 As String = "0000")
В данном примере последний параметр является необязательным (Optional) и по умолчанию равен "0000".
В главе 4 описана перегрузка (overloading) —другой способ определения функций с необязательными параметрами.
VB .NET также позволяет определять процедуры и функции с произвольным количеством аргументов. Для этого в качестве параметра передается массив с ключевым словом РаramАrrау, как в следующем примере:
Function AddThemUp(ByVal ParamArray stuff() As Double) As Double
Dim total As Double = 0
Dim Number As Double = 0
Dim I As Integer
For I = 0 To UBound(stuff)
total = total + stuff(I)
Next
Return total End Function
Пример использования функции:
x = AddThemUp(3, 4. 5. 6)
В результате переменной х присваивается значение 18.
 
Именованные аргументы
При вызове функций и процедур с большим количеством параметров (особенно необязательных) существует такая элегантная возможность, как передача именованных аргументов. Если значения параметров при вызове передаются в виде «имя -:=значение», вам не придется беспокоиться о соблюдении порядка аргументов (регистр символов в именах игнорируется). В отличие от прежних версий VB, где именованные аргументы то работали, то нет, в VB .NET они работают всегда.
Именованные аргументы разделяются запятыми. При разумном выборе имен параметров именованные аргументы заметно упрощают чтение программы, особенно при большом количестве необязательных аргументов. Для примера возьмем приведенный выше заголовок функции ProcessAddress:
Sub ProcessAddress(TheName As String.
Address As String. City As String. State As String,
ZipCode As String, Optional ZipPlus4 As String = "0000")
Вызов этой процедуры может выглядеть так:
ProcessAddress(Address := "The Whitehouse"
Name := "GeorgeW",
City := "DC". _
State:= String.Empty. _
ZipCode:= "12345")
Обратите внимание: порядок перечисления аргументов отличается от заданного в заголовке процедуры.
 
Рекурсия
В VB .NET, как и в любом сколько-нибудь серьезном языке программирования, поддерживается рекурсия — решение задач посредством сведения их к более простым задачам того же типа. Одним из стандартных примеров рекурсивного решения является перебор дерева каталогов на диске (см. главу 9).
На концептуальном уровне рекурсивное решение выглядит следующим образом:
Решение задачи с применением рекурсии
If задача тривиальна
Решить Else
Упростить задачу, сводя ее к однотипной, но более простой задаче
Решить более простую задачу с применением рекурсии
End If
(Возможно) Объединить решение простой задачи (или задач)
с решением исходной задачи.
Рекурсивная функция или процедура постоянно вызывает сама себя, непрерывно упрощая задачу до тех пор, пока ее решение не станет тривиальным; в этот момент задача решается, и происходит возврат к предыдущему уровню. Применение рекурсии нередко связано с принципиальным изменением подхода к некоторым задачам, порождающим особенно элегантные решения и столь же элегантные программы (кстати, многие алгоритмы сортировки — такие, как встроенный метод Sort класса .NET Array, — основаны на принципе рекурсии).
В качестве примера мы рассмотрим программу поиска наибольшего общего делителя двух целых чисел (то есть наибольшего целого числа, на которое они оба делятся без остатка). Пример:

  • НОД(4,6) = 2 (наибольшее число, на которое 4 и 6 делятся без остатка).
  • НОД(12,7) - 1 (числа 12 и 7 не делятся ни на одно целое число, большее 1).

Около 2000 лет назад Евклид предложил следующий алгоритм вычисления НОД двух целых чисел а и b:

  • Если а делится на b, НОД= b. В противном случае НОД (а, b) = НОД (b, a Mod b)

Вспомним, что функция Mod возвращает остаток от целочисленного деления, а выражение a Mod b,равно 0 лишь в том случае, если а кратно b. Пример:
НОД(126.12)=НОД (12. 126 Mod 12)=НОД (12,6) - 6
Ниже приведен пример рекурсивной функции для вычисления НОД. В строке, выделенной жирным шрифтом, функция GCD вызывает сама себя для более простого случая:
Option Strict On Module Modulel
Function GCD(ByVal p As Long, ByVal q As Long) As Long
If Q Mod P = 0 Then
Return P Else
Return GCD(Q, P Mod Q)
End If
End Function Public Sub Main()
Console.WriteLine("The GCD of 36 and 99 is " & GCD(36. 99))
Console. ReadLine()
End Sub
End Module
Сначала обрабатывается тривиальный случай Q Mod P = 0. Если это условие не выполняется, функция GCD снова вызывает себя для более простого случая, поскольку в результате применения Mod мы переходим к меньшим числам. В приведенном примере объединять результаты не нужно (как, например, в функции сортировки).

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика