Процедуры
В отличие от
функций, процедуры не возвращают
конкретных значений. Вызов
процедур осуществляется по имени.
Непустые списки аргументов всегда
заключаются в круглые скобки. В
приведенном ниже примере строка с
вызовом процедуры выделена жирным
шрифтом:
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
немедленно передает управление
вызывающей стороне (если не
определена секция Finally — см. главу 7):
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, — основаны на
принципе рекурсии).
В качестве
примера мы рассмотрим программу
поиска наибольшего общего делителя
двух целых чисел (то есть
наибольшего целого числа, на
которое они оба делятся без остатка).
Пример:
Около 2000
лет назад Евклид предложил
следующий алгоритм вычисления
НОД двух целых чисел а и 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 мы
переходим к меньшим числам. В
приведенном примере объединять
результаты не нужно (как, например,
в функции сортировки).